在Doctrine QueryBuilder中计算行数

Acy*_*yra 190 symfony doctrine-orm

我正在使用Doctrine的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();
Run Code Online (Sandbox Code Playgroud)

我只想对此查询运行计数以获取总行数,但不返回实际结果.(在此计数查询之后,我将使用maxResults进一步修改查询以进行分页.)

Cer*_*rad 456

就像是:

$qb = $entityManager->createQueryBuilder();
$qb->select('count(account.id)');
$qb->from('ZaysoCoreBundle:Account','account');

$count = $qb->getQuery()->getSingleScalarResult();
Run Code Online (Sandbox Code Playgroud)

编辑

有些人认为表达式比使用直接DQL更好.有人甚至编辑了一个四年前的答案.我把他的编辑推回去.去搞清楚.

  • +1使用getSingleScalarResult().在`$ query-> getResult()`上使用`count()`实际上是让查询返回结果(这是他*不想要的).我认为这应该是接受的答案 (49认同)
  • 最便携的方法是`$ qb-> select($ qb-> expr() - > count('account.id'))` (17认同)
  • 他接受了你的回答,所以我觉得一切都很好.我的印象是他只想要一个计数而没有实际检索我的例子显示的行的开销.当然没有理由不在哪里添加条件. (4认同)
  • 谁能解释为什么我必须使用 `select('count(account.id)')` 而不是 `select('count(account)')` ? (3认同)

Hap*_*der 49

以下是格式化查询的另一种方法:

return $repository->createQueryBuilder('u')
            ->select('count(u.id)')
            ->getQuery()
            ->getSingleScalarResult();
Run Code Online (Sandbox Code Playgroud)

  • 你可以写这个`return($ qb = $ repository-> createQueryBuilder('u')) - > select($ qb-> expr() - > count('u.id')) - > getQuery() - > getSingleScalarResult();` (3认同)

luc*_*nov 22

最好将使用数据库的所有逻辑移到存储库中.

所以在控制器中你写

/* you can also inject "FooRepository $repository" using autowire */
$repository = $this->getDoctrine()->getRepository(Foo::class);
$count = $repository->count();
Run Code Online (Sandbox Code Playgroud)

并在 Repository/FooRepository.php

public function count()
{
    $qb = $repository->createQueryBuilder('t');
    return $qb
        ->select('count(t.id)')
        ->getQuery()
        ->getSingleScalarResult();
}
Run Code Online (Sandbox Code Playgroud)

$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();
}
Run Code Online (Sandbox Code Playgroud)

还要考虑缓存查询结果 - 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();
}
Run Code Online (Sandbox Code Playgroud)

在一些简单的情况下,使用EXTRA_LAZY实体关系很好
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html


Nat*_*Kot 17

如果您需要计算更复杂的查询groupBy,having等等...您可以借用Doctrine\ORM\Tools\Pagination\Paginator:

$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($query);
$totalRows = count($paginator);
Run Code Online (Sandbox Code Playgroud)

  • 有用,但请注意:此解决方案适用于单个实体的查询 - 具有复杂的select语句,它只会拒绝工作. (8认同)

Sła*_*nia 8

因为Doctrine 2.6可以count()直接使用方法EntityRepository.有关详细信息,请参阅链接

https://github.com/doctrine/doctrine2/blob/77e3e5c96c1beec7b28443c5b59145eeadbc0baf/lib/Doctrine/ORM/EntityRepository.php#L161


Ser*_*hey 6

使用分组,联合和东西的示例.

问题:

 $qb = $em->createQueryBuilder()
     ->select('m.id', 'rm.id')
     ->from('Model', 'm')
     ->join('m.relatedModels', 'rm')
     ->groupBy('m.id');
Run Code Online (Sandbox Code Playgroud)

为了这个工作可能的解决方案是使用自定义保温器和这个奇怪的东西称为'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);
Run Code Online (Sandbox Code Playgroud)

  • 我宁愿写一个原生查询而不是处理Rube Goldberg代码. (7认同)

Sta*_*arx 5

对于只使用 Doctrine DBAL 而不是 Doctrine ORM 的人,他们将无法访问该getQuery()方法,因为它不存在。他们需要执行以下操作。

$qb = new QueryBuilder($conn);
$count = $qb->select("count(id)")->from($tableName)->execute()->fetchColumn(0);
Run Code Online (Sandbox Code Playgroud)


Ole*_*ets 5

要在一定数量的项目(偏移量)之后计算项目,在这种情况下不能应用 $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;
Run Code Online (Sandbox Code Playgroud)

有人知道更干净的方法吗?