2012-11-13 14 views
10

Ho un problema durante il tentativo di utilizzare QueryBuilder O DQL.Utilizzo di JOIN in Symfony2/Doctrine SQL

Ho la seguente relazione:

utente < -1: n-> Profilo < -n: m-> RouteGroup < -1: n-> Percorso

Vorrei fare un DQL che elenca tutti i percorsi a cui un utente specifico ha accesso. posso ottenere queste informazioni con il seguente codice:

$usr = $this->container->get('security.context')->getToken()->getUser(); 
foreach ($usr->getProfiles() as $profile){ 
    foreach ($profile->getRoutegroups() as $routegroup){ 
     var_dump($routegroup->getRoutes()->toArray()); 
    } 
} 

Per ovvia ragione non posso utilizzare questo codice, altrimenti mi sovraccaricare il mio server, LOL.

ho provato i seguenti approcci:

DQL:

$em->createQuery('SELECT p FROM CRMCoreBundle:User u 
        JOIN CRMCoreBundle:Profile p 
        JOIN CRMCoreBundle:RoleGroup rg 
        JOIN CRMCoreBundle:Role r 
        WHERE 
        u.id=:user') 
     ->setParameter('user', $user->getId()) 
     ->getResult(); 

QueryBuilder (Ho provato ad utilizzare u.profiles - il nome della relazione al posto del soggetto - ma questo non ha funzionato anche):

$em->createQueryBuilder() 
     ->select('r') 
     ->from('CRMCoreBundle:User', 'u') 
     ->innerJoin('u.profiles','p') 
     ->where('u.id = :user_id') 
     ->setParameter('user_id', $user->getId()) 
     ->getQuery() 
     ->getResult(); 

Qualcuno può aiutare per favore ???

UPDATE: Ho provato la soluzione di Zeljko e fatto questo script:

return $this->getEntityManager() 
     ->createQueryBuilder() 
     ->select('u, r') 
     ->from('CRMCoreBundle:User', 'u') 
     ->innerJoin('u.profiles','p') 
     ->innerJoin('p.routegroups','rg') 
     ->innerJoin('rg.routes','r') 
     ->where('u.id = :user_id')->setParameter('user_id', $user->getId()) 
     ->getQuery() 
     ->getResult(); 

ma ho ottenuto questo errore:

The parent object of entity result with alias 'r' was not found. The parent alias is 'rg'. 

Se cambio "-> selezionare ('u, r')" a "-> selezionare ('r')" ottengo questo:

[Semantical Error] line 0, col -1 near 'SELECT r FROM': Error: Cannot select entity through identification variables without choosing at least one root entity alias. 
+1

Per rispondere al tuo aggiornamento, non puoi semplicemente selezionare u e r .. anche tutto ciò che è lungo il percorso deve essere selezionato. quindi è necessario selezionare ('u, p, rg, r') – intrepion

risposta

20

Dopo aver provato alcune alternative, ho scoperto che potevo effettuare una ricerca inversa, iniziando dalle rotte agli utenti. La soluzione era la seguente:

return $this->getEntityManager() 
     ->createQueryBuilder() 
     ->select('r') 
     ->from('CRMCoreBundle:Route', 'r') 
     ->innerJoin('r.routegroup','rg') 
     ->innerJoin('rg.profiles','p') 
     ->innerJoin('p.users','u') 
     ->where('u.id = :user_id') 
     ->setParameter('user_id', $user->getId()) 
     ->getQuery() 
     ->getResult(); 
+2

Ora dovresti cercare di imparare la differenza tra join sinistro e inner-join, sono molto diversi e innerjoin può farti risparmiare un sacco di mal di testa. Modo più semplice; creare una categoria ha una relazione con molti prodotti. Quando recuperi le categorie, esegui innerJoin dei prodotti; otterrete solo categorie che contengono effettivamente prodotti. Davvero interessante, specialmente quando lo abbini alla clausola "WITH". – Zeljko

+0

Nessun problema. Conosco già la differenza tra join interno e sinistro. –

3

Nella tua DQL, state cercando di caricare gli utenti bu t hai chiesto come recuperare percorsi. Di cosa hai veramente bisogno?

In ogni caso, in RoutesRepository:

$this->createQueryBuilder("r") 
    ->innerJoin("r.Profiles", "p") 
    ->innerJoin("p.User", "u") 
    ->where("u=:user")->setParameter("user", $user) 

non potrebbero comprendere la relazione, ma penso che si può cambiare questo in modo da riflettere il proprio codice. Devi usare innerJoin, non leftJoin.

+0

Ciao, ho provato la tua soluzione ma ho avuto un altro problema. Ho aggiornato la domanda di cui sopra. Puoi dare un'occhiata, per favore? Grazie –

3

Non sono un esperto di Doctrine, ma ho appena risolto un problema molto simile. Ho risolto il problema includendo tutte le entità che stavi utilizzando nei join nella parte SELECT dell'istruzione.

Non ho provato questo, ma questo dovrebbe funzionare.

$em->createQuery('SELECT u, p, rg, r FROM CRMCoreBundle:User u 
       JOIN CRMCoreBundle:Profile p 
       JOIN CRMCoreBundle:RoleGroup rg 
       JOIN CRMCoreBundle:Role r 
       WHERE 
       u.id=:user') 
    ->setParameter('user', $user->getId()) 
    ->getResult(); 

non so esattamente perché, ma se non si include le entità poi l'idratante non conoscono gli alias che si sta utilizzando per le entità.

Spero che questo aiuti.