2012-12-27 17 views
5

Dla projektu muszę podać mnóstwo różnych danych w formacie JSON. Wszystkie informacje będą używane na tej samej stronie, więc pojedyncze połączenie spowoduje najmniejszy narzut. Wszystkie informacje dotyczą tego samego obiektu bazy danych i są niezbędne na stronie. Zasadniczo jest to zbiór liczników ilości obiektów, które są jednego lub więcej określonego rodzaju (wszystkie typy to booleany) i musimy znać wiele różnych odmian tego. Użyłem kodu poniżej, ale mój współpracownik uważa, że ​​sposób, w jaki umieściłem go na liście JSON, jest nieco niezgrabny i kod może mieć większą wydajność. Jak mogę poprawić ten kod?Wielokrotne zapytanie COUNT na tym samym typie jednostki za pomocą Symfony 2.1 i Doctrine 2

public function getContactsStatisticsAction() 
{ 
    $response = new Response(); 
    $json = array(); 
    $em = $this->getDoctrine()->getEntityManager(); 
    $cr = $em->getRepository('BlaCoreBundle:Company'); 

    $json['numberOfCompanies'] = $cr->numberOfCompanies(); 
    $json['numberOfAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true)); 
    $json['numberOfCompetitors'] = $cr->numberOfCompanies(array("typeCompetitor" => true)); 
    $json['numberOfSuppliers'] = $cr->numberOfCompanies(array("typeSupplier" => true)); 
    $json['numberOfOthers'] = $cr->numberOfCompanies(array("typeOther" => true)); 
    $json['numberOfUnassigned'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => false,"typeSupplier" => false,"typeOther" => false)); 

    $json['numberOfJustAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => false, "typeSupplier" => false)); 
    $json['numberOfJustCompetitors'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => false, "typeSupplier" => false)); 
    $json['numberOfJustSuppliers'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => false, "typeSupplier" => false)); 

    $json['numberOfCompetitorAndAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => true, "typeSupplier" => false)); 
    $json['numberOfCompetitorAndSuppliers'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => true, "typeSupplier" => true)); 
    $json['numberOfSupplierAndAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => false, "typeSupplier" => true)); 
    $json['numberOfCompaniesAndAccountsAndSuppliers'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => true, "typeSupplier" => true)); 

    $response->setContent(json_encode($json)); 
    return $response; 
} 


public function numberOfCompanies($filters = array()) 
{ 
    $qb = $this->getEntityManager()->createQueryBuilder(); 
    $qb->select('count(c.id)'); 
    $qb->from('BlaCoreBundle:Company', 'c'); 
    $sizeFilters = count ($filters); 
    $keys = array_keys($filters); 
    if($sizeFilters >= 1){ 
     $qb->where('c.' . $keys[0] . ' = ' . (int) $filters[$keys[0]]); 
    } 
    for($i = 1; $i < $sizeFilters; $i++){ 
     $qb->andWhere('c.' . $keys[$i] . ' = ' . (int) $filters[$keys[$i]]); 
    } 
    return $qb->getQuery()->getSingleScalarResult(); 
} 
+0

Myślę, że to należy do http://codereview.stackexchange.com/. –

+0

W porządku, dam też tam stanowisko. Dziękuję Ci! – Kristof

Odpowiedz

3

Twoi koledzy mają rację. Powinieneś uzyskać wszystkie te skalarne wyniki w jednym zapytaniu. W ten sposób zminimalizujesz liczbę połączeń.

Temat został rozwiązany w this answer dla przypadku innego niż Doctrine.

Taki użytkownik również zadał to interesujące pytanie here, ale nikt nie odpowiedział.

Właściwie myślę, że nie ma sposobu, aby rozwiązać ten rodzaj zapytania z QueryBuilder lub DQL. Również w oficjalnych dokumentach dla Doctrine2.2 nie ma przykładów JOIN na na .

Co można spróbować coś jak następującego zapytania DQL:

return $this->getEntityManager()->createQuery(
    SELECT COUNT(c1) AS C1, COUNT(c2) AS C2, COUNT(c3) AS C3 FROM 
    BlaCoreBundle:Company c1, BlaCoreBundle:Company c2, BlaCoreBundle:Company c3 
    WHERE c1.prop1 = 'xxx' AND c2.prop2 > '100' AND c3.prop3 LIKE '%XYZ%')    
    ->getResult(); 

gdzie oczywiście klauzule Gdzie są ogólne przykłady. To zapytanie zwróci tablicę o jednym rozmiarze, z C1, C2 i C3 jako kluczem dla zliczonych wartości. Oczywiście korzystanie z JOIN i cokolwiek innego jest trudne, ale zawsze możesz użyć WHERE IN (SELECT...) i WHERE EXISTS (SELECT...), np.

SELECT COUNT(c1) AS C1, COUNT(c2) AS C2, COUNT(c3) AS C3 FROM 
    BlaCoreBundle:Company c1, BlaCoreBundle:Company c2, BlaCoreBundle:Company c3 
    WHERE c1.prop1 = 'xxx' AND c2.prop2 > '100' AND c3.prop3 LIKE '%XYZ%' 
AND EXISTS (SELECT x FROM BlaCoreBundle:Entity x JOIN x.company comp WHERE x.prop = "valye" AND comp = c1)    
+0

Dodałem możliwe rozwiązanie! Próbowałem i działa bardzo dobrze. – JeanValjean