symfony - Contar filas en Doctrine QueryBuilder
symfony doctrine get max value (9)
Agregar el siguiente método a su repositorio debería permitirle llamar $repo->getCourseCount()
desde su Controlador.
/**
* @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();
}
Estoy usando Doctrine''s QueryBuilder para crear una consulta, y quiero obtener el recuento total de los resultados de la consulta.
$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();
Solo quiero ejecutar un conteo en esta consulta para obtener el total de filas, pero no devolver los resultados reales. (Después de esta consulta de conteo, voy a modificar aún más la consulta con maxResults para la paginación).
Algo como:
$qb = $entityManager->createQueryBuilder();
$qb->select(''count(account.id)'');
$qb->from(''ZaysoCoreBundle:Account'',''account'');
$count = $qb->getQuery()->getSingleScalarResult();
EDITAR
Algunas personas sienten que las expresiones son de alguna manera mejor que solo usar DQL directo. Uno incluso llegó a editar una respuesta de cuatro años. Le devolví su edición. Imagínate.
Aquí hay otra forma de formatear la consulta:
return $repository->createQueryBuilder(''u'')
->select(''count(u.id)'')
->getQuery()
->getSingleScalarResult();
Desde Doctrine 2.6
, es posible utilizar el método count()
directamente desde EntityRepository
. Para más detalles, vea el enlace.
Ejemplo de trabajo con agrupación, unión y otras cosas.
Problema:
$qb = $em->createQueryBuilder()
->select(''m.id'', ''rm.id'')
->from(''Model'', ''m'')
->join(''m.relatedModels'', ''rm'')
->groupBy(''m.id'');
Para que esto funcione, la solución posible es usar un hidratador personalizado y esta cosa extraña llamada ''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);
Es mejor mover toda la lógica del trabajo con la base de datos a los repositores.
Entonces en el controlador escribes
$repository = $this->getDoctrine()->getRepository(''FooBundle:Foo'');
$count = $repository->count();
Y en FooBundle/Repository/FooRepository.php
public function count()
{
$qb = $repository->createQueryBuilder(''t'');
return $qb
->select(''count(t.id)'')
->getQuery()
->getSingleScalarResult();
}
Es mejor mover $qb = ...
para separar la fila en caso de que quiera hacer expresiones complejas como
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();
}
También piense en el almacenamiento en caché del resultado de su consulta: 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();
}
En algunos casos simples que usan relaciones de entidades EXTRA_LAZY
es bueno
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html
Para contar elementos después de cierto número de elementos (desplazamiento), $ qb-> setFirstResults () no se puede aplicar en este caso, ya que no funciona como una consulta, sino como un resultado de consulta para un rango de elementos seleccionados ( es decir, setFirstResult no se puede usar para registrar con COUNT en absoluto). Entonces, para contar los artículos que quedan, simplemente hice lo siguiente:
//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;
¿Alguien sabe más forma limpia de hacerlo?
Para las personas que solo usan Doctrine DBAL y no Doctrine ORM, no podrán acceder al método getQuery()
porque no existe. Necesitan hacer algo como lo siguiente.
$qb = new QueryBuilder($conn);
$count = $qb->select("count(id)")->from($tableName)->execute()->fetchColumn(0);
Si necesita contar una consulta más compleja, con groupBy
, having
etc ... Puede tomar prestado de Doctrine/ORM/Tools/Pagination/Paginator
:
$paginator = new /Doctrine/ORM/Tools/Pagination/Paginator($query);
$totalRows = count($paginator);