Подсчет строк в Doctrine QueryBuilder
Я использую QueryBuilder доктрины для построения запроса, и я хочу получить общее количество результатов от запроса.
$repository = $em->getRepository('FooBundle:Foo');
$qb = $repository->createQueryBuilder('n')
->where('n.bar = :bar')
->setParameter('bar', $bar);
$query = $qb->getQuery();
//this doesn't work
$totalrows = $query->getResult()->count();
Я просто хочу запустить подсчет по этому запросу, чтобы получить общие строки, но не возвращать фактические результаты. (После этого запроса count я собираюсь дополнительно изменить запрос с помощью maxResults для разбиения на страницы.)
9 ответов:
что-то типа:
$qb = $entityManager->createQueryBuilder(); $qb->select('count(account.id)'); $qb->from('ZaysoCoreBundle:Account','account'); $count = $qb->getQuery()->getSingleScalarResult();EDIT
некоторые люди считают, что выражения каким-то образом лучше, чем просто использовать прямой DQL. Один даже зашел так далеко, что отредактировал четырехлетний ответ. Я откатил его редактирование назад. Иди разберись.
вот еще один способ формате запрос:
return $repository->createQueryBuilder('u') ->select('count(u.id)') ->getQuery() ->getSingleScalarResult();
лучше перенести всю логику работы с базой данных в репозитории.
так в контроллере вы пишете
/* you can also inject "FooRepository $repository" using autowire */ $repository = $this->getDoctrine()->getRepository(Foo::class); $count = $repository->count();и
Repository/FooRepository.phppublic function count() { $qb = $repository->createQueryBuilder('t'); return $qb ->select('count(t.id)') ->getQuery() ->getSingleScalarResult(); }лучше двигаться
$qb = ...в отдельной строке в случае, если вы хотите сделать сложные выражения, какpublic function count() { $qb = $repository->createQueryBuilder('t'); return $qb ->select('count(t.id)') ->where($qb->expr()->isNotNull('t.fieldName')) ->andWhere($qb->expr()->orX( $qb->expr()->in('t.fieldName2', 0), $qb->expr()->isNull('t.fieldName2') )) ->getQuery() ->getSingleScalarResult(); }также подумайте о кэшировании результата запроса - http://symfony.com/doc/current/reference/configuration/doctrine.html#caching-drivers
public function count() { $qb = $repository->createQueryBuilder('t'); return $qb ->select('count(t.id)') ->getQuery() ->useQueryCache(true) ->useResultCache(true, 3600) ->getSingleScalarResult(); }In некоторые простые случаи с использованием
EXTRA_LAZYотношения сущностей good
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html
Если вам нужно посчитать более сложный запрос, с
groupBy,havingetc... Вы можете взять уDoctrine\ORM\Tools\Pagination\Paginator:$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($query); $totalRows = count($paginator);
пример работы с группировкой, Союз и прочее.
:$qb = $em->createQueryBuilder() ->select('m.id', 'rm.id') ->from('Model', 'm') ->join('m.relatedModels', 'rm') ->groupBy('m.id');для этого, чтобы работать возможное решение-использовать пользовательский гидратор и эту странную вещь называется 'CUSTOM OUTPUT WALKER HINT':
class CountHydrator extends AbstractHydrator { const NAME = 'count_hydrator'; const FIELD = 'count'; /** * {@inheritDoc} */ protected function hydrateAllData() { return (int)$this->_stmt->fetchColumn(0); } } class CountSqlWalker extends SqlWalker { /** * {@inheritDoc} */ public function walkSelectStatement(AST\SelectStatement $AST) { return sprintf("SELECT COUNT(*) AS %s FROM (%s) AS t", CountHydrator::FIELD, parent::walkSelectStatement($AST)); } } $doctrineConfig->addCustomHydrationMode(CountHydrator::NAME, CountHydrator::class); // $qb from example above $countQuery = clone $qb->getQuery(); // Doctrine bug ? Doesn't make a deep copy... (as of "doctrine/orm": "2.4.6") $countQuery->setParameters($this->getQuery()->getParameters()); // set custom 'hint' stuff $countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, CountSqlWalker::class); $count = $countQuery->getResult(CountHydrator::NAME);
для подсчета элементов после некоторого количества элементов (смещение), $qb->setFirstResults () не может быть применен в этом случае, так как он работает не как условие запроса, а как смещение результата запроса для диапазона выбранных элементов (т. е. setFirstResult не может быть использован вместе с COUNT вообще). Поэтому для подсчета предметов, которые остались я просто сделал следующее:
//in repository class: $count = $qb->select('count(p.id)') ->from('Products', 'p') ->getQuery() ->getSingleScalarResult(); return $count; //in controller class: $count = $this->em->getRepository('RepositoryBundle')->... return $count-$offset;кто-нибудь знает более чистый способ сделать это?
для людей, которые используют только доктрину DBAL, а не доктрину ORM, они не смогут получить доступ к
getQuery()метод, потому что его не существует. Они должны сделать что-то вроде следующего.$qb = new QueryBuilder($conn); $count = $qb->select("count(id)")->from($tableName)->execute()->fetchColumn(0);
С
Doctrine 2.6можно использоватьcount()способ прямо изEntityRepository. Подробности смотрите по ссылке.
добавление следующего метода в репозиторий должно позволить вам вызвать
$repo->getCourseCount()из вашего контроллера./** * @return array */ public function getCourseCount() { $qb = $this->getEntityManager()->createQueryBuilder(); $qb ->select('count(course.id)') ->from('CRMPicco\Component\Course\Model\Course', 'course') ; $query = $qb->getQuery(); return $query->getSingleScalarResult(); }
Comments