2012-12-27 14 views
5

Per un progetto è necessario fornire un carico di dati diversi in formato JSON. Tutte le informazioni verranno utilizzate sulla stessa pagina in modo che una singola chiamata possa comportare il minimo sovraccarico. Le informazioni riguardano tutte lo stesso oggetto del database e sono tutte necessarie nella pagina. Fondamentalmente è una raccolta di conteggi della quantità di oggetti che sono di uno o più di un certo tipo (i tipi sono tutti i booleani) e abbiamo bisogno di conoscere molte diverse varianti di questo. Ho usato il codice qui sotto ma il mio collega crede che il modo in cui l'ho inserito nella lista JSON sia un po 'goffo e il codice potrebbe avere prestazioni migliori. Come posso migliorare questo codice?Più query COUNT sullo stesso tipo di entità utilizzando Symfony 2.1 e 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

Penso che questo appartiene a http://codereview.stackexchange.com/. –

+0

Va bene, ci metterò anche un post. Grazie! – Kristof

risposta

3

I tuoi colleghi hanno ragione. Dovresti ottenere tutti i risultati scalari in una singola query. In questo modo ridurrai al minimo il numero di connessioni.

L'argomento è risolto in this answer per un caso non di Doctrine.

Tale utente ha anche fatto questa domanda interessante here, ma nessuno ha risposto.

In realtà credo che non v'è alcun modo per risolvere questo tipo di query con QueryBuilder o con DQL. Anche nei documenti ufficiali per Doctrine2.2 non ci sono esempi di JOIN su un SELECT.

Che cosa si può provare è qualcosa di simile alla seguente query 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(); 

in cui, naturalmente, le clausole in cui sono esempi generali. Questa query restituirà un array di una dimensione, con C1, C2 e C3 come chiave per i valori conteggiati. Certo, diventa difficile utilizzare JOIN e qualsiasi cosa tu abbia bisogno, ma puoi sempre usare WHERE IN (SELECT...) e WHERE EXISTS (SELECT...), ad es.

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

Ho aggiunto una possibile soluzione! L'ho provato e funziona molto bene. – JeanValjean

Problemi correlati