Вот что я сделал, чтобы решить эту проблему без каких-либо дополнительных запросов:
Проблема
, необходимые для добавления пользовательских полей COUNT для типичного результирующего набора, используемого с Symfony пейджера. Однако, как мы знаем, Propel не поддерживает это в коробке. Таким образом, простое решение, чтобы просто сделать что-то вроде этого в шаблоне:
foreach ($pager->getResults() as $project):
echo $project->getName() . ' and ' . $project->getNumMembers()
endforeach;
Где getNumMembers()
запускает отдельный запрос COUNT для каждого $project
объекта. Конечно, мы знаем, что это крайне неэффективно, потому что вы можете делать COUNT «на лету», добавляя его в качестве столбца в исходный запрос SELECT, сохраняя запрос для каждого отображаемого результата.
У меня было несколько разных страниц, отображающих этот результирующий набор, все с использованием разных критериев. Поэтому написать собственную строку запроса SQL с PDO напрямую было бы слишком сложной задачей, так как мне пришлось бы попасть в объект Criteria и запутаться, пытаясь сформировать строку запроса на основе того, что было в ней!
Итак, что я сделал в конце, избегает всего этого, позволяя собственному коду Propel работать с критериями и создавать SQL как обычно.
1 - Сначала создайте [get/set] методы NumMembers() эквивалентного доступа/мутатора в объекте модели, который возвращается с помощью doSelect(). Помните, что аксессуар больше не выполняет запрос COUNT, он просто сохраняет свое значение.
2 - Идите в класс сверстников и переопределить родительский doSelect() метод и скопировать весь код из него именно так, как это
3 - Удалить этот бит, потому что getMixerPreSelectHook является частным методом базового партнера (или скопируйте его в партнера, если вам это нужно):
// symfony_behaviors behavior
foreach (sfMixer::getCallables(self::getMixerPreSelectHook(__FUNCTION__)) as $sf_hook)
{
call_user_func($sf_hook, 'BaseTsProjectPeer', $criteria, $con);
}
4 - Теперь добавьте пользовательское поле COUNT методу doSelect в классе сверстников:
// copied into ProjectPeer - overrides BaseProjectPeer::doSelectJoinUser()
public static function doSelectJoinUser(Criteria $criteria, ...)
{
// copied from parent method, along with everything else
ProjectPeer::addSelectColumns($criteria);
$startcol = (ProjectPeer::NUM_COLUMNS - ProjectPeer::NUM_LAZY_LOAD_COLUMNS);
UserPeer::addSelectColumns($criteria);
// now add our custom COUNT column after all other columns have been added
// so as to not screw up Propel's position matching system when hydrating
// the Project and User objects.
$criteria->addSelectColumn('COUNT(' . ProjectMemberPeer::ID . ')');
// now add the GROUP BY clause to count members by project
$criteria->addGroupByColumn(self::ID);
// more parent code
...
// until we get to this bit inside the hydrating loop:
$obj1 = new $cls();
$obj1->hydrate($row);
// AND...hydrate our custom COUNT property (the last column)
$obj1->setNumMembers($row[count($row) - 1]);
// more code copied from parent
...
return $results;
}
Вот и все. Теперь у вас есть дополнительное поле COUNT, добавленное к вашему объекту, без отдельного запроса, чтобы получить его, когда вы выплевываете результаты. Единственным недостатком этого решения является то, что вам пришлось скопировать весь родительский код, потому что вам нужно добавить бит прямо посередине. Но в моей ситуации это казалось небольшим компромиссом, чтобы сохранить все эти запросы и не писать собственную строку SQL-запроса.
Спасибо за этот ответ - это помогло мне решить другую проблему! – 2008-11-03 16:01:15