Doktrin SorguBuilder'deki Satırları Say


198

Bir sorgu oluşturmak için Doctrine'nın QueryBuilder kullanıyorum ve sorgudan sonuçların toplam sayısını almak istiyorum.

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

Sadece toplam satırları almak için bu sorgu üzerinde bir sayı çalıştırmak istiyorum, ancak gerçek sonuçları döndürmek istemiyorum. (Bu sayım sorgusundan sonra, pagination için maxResults ile sorguyu daha fazla değiştireceğim.)


1
sadece sonuç sayısını döndürmek mi istiyorsunuz? kodunuz çok açık değil. getQuery () neden çalışmıyor?
jere


Yanıtlar:


477

Gibi bir şey:

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

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

Bazıları ifadelerin bir şekilde düz DQL kullanmaktan daha iyi olduğunu düşünüyor. Hatta dört yaşındaki bir yanıtı düzenleyecek kadar ileri gitti. Düzenlemesini geri aldım. Git şekil.


Tahminleri olmayan bir sayı istemedi ( bar = $bar);)
Jovan Perovic

4
Cevabınızı kabul etti, sanırım her şey yolunda. Sadece örneğimin gösterdiği satırları almanın yükü olmadan bir sayım istediği izlenimindeydim. Elbette koşulların eklenememesinin bir nedeni yoktur.
Cerad

50
GetSingleScalarResult () kullanmak için +1. kullanarak count()üzerinde $query->getResult()aslında sorgu (o budur sonuç yapıyor vermedi istiyorum). bence bu cevap kabul edilmelidir
jere

18
En taşınabilir yol yapmaktır$qb->select($qb->expr()->count('account.id'))
webbiedave

1
Herkes neden select('count(account.id)')yerine kullanmam gerektiğini açıklayabilir select('count(account)')mi?
Stepan Yudin

51

Sorguyu biçimlendirmenin başka bir yolu:

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

Akıcı arayüzü kullanmak, statik sorgular yazmak istediğinizde çok yardımcı olan farklı bir yaklaşımdır. Örneğin, her yöntemi kendi başına yürütmenin koşullarının nerede olduğu arasında geçiş yapılması gerekiyorsa, bunun da avantajları vardır.
barbieswimcrew

3
Bunu yazabilirsinizreturn ($qb = $repository->createQueryBuilder('u'))->select($qb->expr()->count('u.id'))->getQuery()->getSingleScalarResult();
Barh

25

Veritabanı ile çalışmanın tüm mantığını depolara taşımak daha iyidir.

Yani kontrolörde yazıyorsun

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

Ve Repository/FooRepository.php

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

$qb = ...Gibi karmaşık ifadeler yapmak istemeniz durumunda ayrı bir satıra geçmek daha iyidir

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

Ayrıca sorgu sonucunuzu önbelleğe almayı da düşünün - 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();
}

Bazı basit durumlarda EXTRA_LAZYvarlık ilişkileri kullanmak iyidir
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html


17

Eğer, daha karmaşık bir sorgu saymak ile gerekiyorsa groupBy, havingvb ... Sen ödünç alabilirsiniz Doctrine\ORM\Tools\Pagination\Paginator:

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

8
Yararlı, ancak lütfen unutmayın: Bu çözüm, tek bir varlıktaki sorgular için çalışır - karmaşık seçme ifadeleriyle, sadece çalışmayı reddeder.
Paolo Stefan

Bu çözüm SELECT COUNT(*) AS dctrn_count FROM (_ORIGINAL_SQL_) dctrn_result) dctrn_table, aslında özel bir şey değil, iyi bilinen COUNT (*) çözüm gibi ek sorgu üretir
Vladyslav Kolesov

$ paginator-> getTotalItemCount () da bir çözüm olacaktır
cwhisperer

11

Yana Doctrine 2.6kullanmak mümkündür count()şirketinden yöntem EntityRepository. Ayrıntılar için bağlantıya bakın.

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


Evet, harika bir çözüm gibi görünüyor ve daha basit durumlar için çalışıyor (sayımı filtrelemek için ölçütleri geçebilirsiniz), ancak ilişkilendirmelerle ölçütler için çalışmaya başlayamadım (derneklere göre filtreleme). İlgili yazıya buradan bakın: github.com/doctrine/orm/issues/6290
Wilt

6

Gruplama, birlik ve diğer şeylerle çalışma örneği.

Sorun:

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

Bunun çalışması için olası çözüm özel nemlendirici ve 'ÖZEL ÇIKTI YÜRÜYÜCÜ İPUCU' olarak adlandırılan garip bir şey kullanmaktır:

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 koduyla uğraşmak yerine yerel bir sorgu yazmak istiyorum.
keyboardSmasher

Bu boktan Symfony ne kadar iyi bir örnek: Temel bir günlük SQL sayısı gibi basit bir şey tamamen karmaşık kendi kendine yazılan şeyler ile çözülmesi gerekiyor ... vay, yani, sadece vay! Bu cevap için hala Sergey'e teşekkürler!
Sliq

4

Doctrine ORM'yi değil, yalnızca Doctrine DBAL kullanan kişiler için, var olmadığı için getQuery()yönteme erişemezler . Aşağıdaki gibi bir şey yapmaları gerekiyor.

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

4

Belirli sayıda öğeden (ofset) sonra öğeleri saymak için, sorgu durumunda değil, seçilen bir dizi öğe için sorgu sonucunun ofseti olarak çalıştığından $ qb-> setFirstResults () bu durumda uygulanamaz. yani setFirstResult, hiç COUNT ile birlikte kullanılamaz). Kalan öğeleri saymak için şunları yaptım:

   //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;

Bunu yapmanın daha temiz bir yolunu bilen var mı?


0

Deponuza aşağıdaki yöntemi eklemek $repo->getCourseCount()Denetleyicinizden arama yapmanızı sağlar .

/**
 * @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

Sayma işlevini kullanarak veri sayısını da alabilirsiniz.

$query = $this->dm->createQueryBuilder('AppBundle:Items')
                    ->field('isDeleted')->equals(false)
                    ->getQuery()->count();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.