Doctrine QueryBuilder에서 행 수


197

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();

이 쿼리에서 카운트를 실행하여 총 행을 가져 오지만 실제 결과는 반환하지 않습니다. (이 카운트 쿼리 후에 페이지 매김을 위해 maxResults를 사용하여 쿼리를 추가로 수정하겠습니다.)


1
결과 수를 반환하고 싶습니까? 코드가 명확하지 않습니다. getQuery ()가 작동하지 않는 이유는 무엇입니까?
jere

doctrine2로 페이지 매김을 구축하려면 다음 확장을 살펴보십시오. github.com/beberlei/DoctrineExtensions
Stefan

3
@Stefan은 이제 ORM의 일부입니다. docs.doctrine-project.org/en/latest/tutorials/pagination.html
유진

답변:


474

다음과 같은 것 :

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

$count = $qb->getQuery()->getSingleScalarResult();

어떤 사람들은 단순한 DQL을 사용하는 것보다 표현이 더 좋다고 생각합니다. 한 사람은 네 살짜리 답을 편집하기까지 갔다. 나는 그의 편집을 되 돌렸다. 그림을 이동.


그는 술어 (없이 카운트를 요청하지 않았다 bar = $bar))
조반 Perovic에게

4
그는 당신의 대답을 받아 들였습니다. 나는 내 예제가 보여주는 행을 실제로 검색하는 오버 헤드없이 카운트를 원한다는 인상을 받았습니다. 물론 조건을 추가 할 수없는 이유는 없습니다.
Cerad

50
getSingleScalarResult () 사용시 +1 count()on을 사용 하면 $query->getResult()실제로 쿼리가 결과를 반환하게됩니다 ( 원하는 것이 아닙니다 ). 나는 이것이 대답을 받아 들여야한다고 생각한다
14:30의

18
가장 편리한 방법은$qb->select($qb->expr()->count('account.id'))
webbiedave

1
아무도 내가 select('count(account.id)')대신 사용해야하는 이유를 설명 할 수 select('count(account)')있습니까?
스테판 유딘

51

쿼리를 형식화하는 다른 방법은 다음과 같습니다.

return $repository->createQueryBuilder('u')
            ->select('count(u.id)')
            ->getQuery()
            ->getSingleScalarResult();

유창한 인터페이스를 사용하는 것은 정적 쿼리를 작성하려는 경우 매우 유용한 다른 접근 방식입니다. 예를 들어 각각의 메소드를 자체적으로 실행하는 조건을 토글해야 할 필요가 있다면 이점도 있습니다.
barbieswimcrew

3
당신은 이것을 쓸 수 있습니다return ($qb = $repository->createQueryBuilder('u'))->select($qb->expr()->count('u.id'))->getQuery()->getSingleScalarResult();
Barh

25

데이터베이스 작업의 모든 논리를 리포지토리로 옮기는 것이 좋습니다.

컨트롤러에서

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

그리고 Repository/FooRepository.php

public 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();
}

EXTRA_LAZY엔티티 관계를 사용하는 간단한 경우에는 http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html 이 좋습니다.


17

당신이, 더 복잡한 쿼리를 계산으로해야하는 경우 groupBy, having등 ... 당신은에서 빌릴 수 Doctrine\ORM\Tools\Pagination\Paginator:

$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($query);
$totalRows = count($paginator);

8
유용하지만 참고 사항 :이 솔루션은 복잡한 단일 선택문이있는 단일 엔터티에 대한 쿼리에서 작동하지만 작동을 거부합니다.
Paolo Stefan

이 솔루션 SELECT COUNT(*) AS dctrn_count FROM (_ORIGINAL_SQL_) dctrn_result) dctrn_table은 실제로 특별한 것은 아니지만 알려진 COUNT (*) 솔루션 과 같은 추가 쿼리를 생성 합니다.
Vladyslav Kolesov

$ paginator-> getTotalItemCount ()도 해결책이 될 것입니다
cwhisperer

11

에서 직접 방법 Doctrine 2.6을 사용할 수 있기 때문입니다 . 자세한 내용은 링크를 참조하십시오.count()EntityRepository

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


예, 훌륭한 솔루션처럼 보이며 더 간단한 경우 (카운팅 필터링 기준을 전달할 수 있음)에서는 작동하지만 협회와 관련된 기준 (협회별로 필터링)을 작동시키지 못했습니다. 관련 게시물보기 : github.com/doctrine/orm/issues/6290
Wilt

6

그룹화, 공용체 및 물건을 사용하는 예제.

문제:

 $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);

7
Rube Goldberg 코드를 처리하는 것보다 기본 쿼리를 작성하고 싶습니다.
keyboardSmasher

이것이 교활한 Symfony의 좋은 예입니다. 기본 일상 SQL 수와 같은 간단한 것은 완전히 복잡한 자체 작성 항목으로 해결해야합니다 ... 와우, 내 말은, 그냥 와우! 이 답변에 대해 Sergey에게 감사드립니다!
Sliq

4

Doctrine DBAL 만 사용하고 Doctrine ORM은 사용하지 않는 사람들에게는 getQuery()존재하지 않기 때문에 메소드 에 액세스 할 수 없습니다. 그들은 다음과 같은 일을해야합니다.

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

4

일부 항목 수 (오프셋) 이후에 항목을 계산하려면 $ 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;

아무도 더 깨끗한 방법을 알고 있습니까?


0

리포지토리에 다음 방법을 추가하면 $repo->getCourseCount()Controller에서 호출 할 수 있습니다 .

/**
 * @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();
}

0

count 함수를 사용하여 데이터 수를 얻을 수도 있습니다.

$query = $this->dm->createQueryBuilder('AppBundle:Items')
                    ->field('isDeleted')->equals(false)
                    ->getQuery()->count();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.