मत पंक्तियों की गणना Doctrine QueryBuilder में करें


197

मैं क्वेरी बनाने के लिए Doctrine's 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();

मैं केवल कुल पंक्तियों को प्राप्त करने के लिए इस क्वेरी पर एक गिनती चलाना चाहता हूं, लेकिन वास्तविक परिणाम नहीं लौटाता। (इस गणना क्वेरी के बाद, मैं पृष्ठ पर अंक लगाना के साथ अधिकतम क्वेरी को संशोधित करने जा रहा हूं।)


1
आप केवल परिणामों की संख्या वापस करना चाहते हैं? आपका कोड बहुत स्पष्ट नहीं है। क्यों नहीं काम करता है?
jere

Doctrine2 के साथ पेजिंग के निर्माण के लिए इस विस्तार पर एक नज़र है: github.com/beberlei/DoctrineExtensions
Stefan

3
@ पहले यह अब 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);) के बिना कोई गिनती नहीं
मांगी

4
उसने आपका उत्तर स्वीकार कर लिया, इसलिए मुझे लगता है कि सब ठीक है। मैं इस धारणा के तहत था कि वह केवल वास्तव में पंक्तियों को पुनः प्राप्त करने के बिना एक गिनती चाहता था जो मेरे उदाहरण से पता चलता है। निश्चित रूप से कोई कारण नहीं है कि जहां स्थितियां नहीं जोड़ी जा सकती हैं।
सेराड

50
GetSingleScalarResult () का उपयोग करने के लिए +1। का उपयोग कर count()पर $query->getResult()वास्तव में क्वेरी परिणाम वापस (जो कि वह क्या कर रहा है नहीं था चाहते हैं)। मुझे लगता है कि यह स्वीकार किया जाना चाहिए जवाब
jere

18
सबसे पोर्टेबल तरीका है$qb->select($qb->expr()->count('account.id'))
वेबबिडीव

1
क्या कोई समझा सकता है कि मुझे select('count(account.id)')इसके बजाय क्यों उपयोग करना चाहिए select('count(account)')?
Stepan Yudin

51

यहाँ क्वेरी को प्रारूपित करने का एक और तरीका है:

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

धाराप्रवाह इंटरफ़ेस का उपयोग करना एक अलग दृष्टिकोण है जो उस स्थिति में बहुत मददगार होता है जब आप स्थिर प्रश्न लिखना चाहते हैं। अगर वहाँ टॉगल करने की आवश्यकता है जहाँ उदाहरण के लिए प्रत्येक विधि को निष्पादित करने की शर्तें स्वयं की हैं तो इसके फायदे भी हैं।
22 दिसंबर को barbieswimcrew

3
आप इसे लिख सकते हैंreturn ($qb = $repository->createQueryBuilder('u'))->select($qb->expr()->count('u.id'))->getQuery()->getSingleScalarResult();
बरह

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
उपयोगी, लेकिन कृपया ध्यान दें: यह समाधान एकल इकाई पर प्रश्नों के लिए काम करेगा- जटिल चुनिंदा बयानों के साथ, यह सिर्फ काम करने से इंकार करेगा।
पाओलो स्टीफन

यह समाधान अतिरिक्त क्वेरी उत्पन्न करता है, SELECT COUNT(*) AS dctrn_count FROM (_ORIGINAL_SQL_) dctrn_result) dctrn_tableजो वास्तव में कुछ खास नहीं है, लेकिन ज्ञात COUNT (*) समाधान
व्लादिस्लाव कोल्लोव

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

इसके लिए संभव समाधान के लिए कस्टम हाइड्रेटर का उपयोग करना है और 'CUTOM 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 कोड से निपटने के बजाय केवल एक देशी क्वेरी लिखूंगा।
कीबोर्डस्मैशर

यह एक अच्छा उदाहरण है कि कैसे शिमिती सिम्फनी है: एक साधारण रोजमर्रा की SQL-काउंट की तरह कुछ सरल पूरी तरह से जटिल स्व-लिखित सामान के साथ हल करने की आवश्यकता है ... वाह, मेरा मतलब है, बस वाह! फिर भी इस जवाब के लिए सर्गेई का धन्यवाद!
सालीक

4

जो लोग केवल डॉक्ट्रिन डीबीएएल का उपयोग कर रहे हैं न कि डॉक्ट्रिन ओआरएम का, वे 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()अपने कंट्रोलर से कॉल करने की अनुमति देनी चाहिए ।

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

आप गणना फ़ंक्शन का उपयोग करके डेटा की संख्या भी प्राप्त कर सकते हैं।

$query = $this->dm->createQueryBuilder('AppBundle:Items')
                    ->field('isDeleted')->equals(false)
                    ->getQuery()->count();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.