2015-04-23 26 views
12

Używanie symfony2/doctrine2, Trudno mi zdefiniować indeks dla mojego zapytania.Doctrine QueryBuilder indexBy na złączonej klasie - p jest już zdefiniowany Błąd

Mój kod:

$queryBuilder = $this->_em 
     ->createQueryBuilder() 
     ->select('u, uis, cost, p, stock') 
     ->from('AppBundle:FoodAnalytics\UserIngredient', 'u', 'p.id') 
     ->leftJoin('u.product', 'p') 
     ->leftJoin('u.numberObjects', 'stock') 
     ->leftJoin('u.userIngredientSuppliers', 'uis') 
     ->leftJoin('uis.numberObjects', 'cost') 
     ->where('u.user = ?1') 
     ->setParameter(1, $portfolioUser) 
     ; 

pojawia się następujący błąd:

[Semantical Error] line 0, col 110 near 'p LEFT JOIN u.numberObjects': Error: 'p' is already defined. 
500 Internal Server Error - QueryException 
1 linked Exception: QueryException » 

[1/2] QueryException: SELECT u, uis, cost, p, stock FROM AppBundle:FoodAnalytics\UserIngredient u INDEX BY p.id LEFT JOIN u.product p LEFT JOIN u.numberObjects stock LEFT JOIN u.userIngredientSuppliers uis LEFT JOIN uis.numberObjects cost WHERE u.user = ?1 + 

Korzystanie u.product pojawia się następujący błąd:

[Semantical Error] line 0, col 87 near 'product LEFT': Error: Invalid PathExpression. Must be a StateFieldPathExpression. 
500 Internal Server Error - QueryException 
1 linked Exception: QueryException » 

używając tylko product, pojawia się następujący Błąd:

[Semantical Error] line 0, col 85 near 'product LEFT': Error: 'product' does not point to a Class. 
500 Internal Server Error - QueryException 
1 linked Exception: QueryException » 

Działa dobrze, jeśli używam u.id Czy mogę używać indeksu tylko z pola z tej samej tabeli?

Co mogę zrobić, aby działało?

Thansk dużo!

EDIT:

Jako tymczasowy fix używam:

$result = $queryBuilder->getQuery()->getResult(); 
    $result = array_combine(array_map(function(UserIngredient $userIngredient){ 
       return $userIngredient->getProduct()->getId(); 
      }, $result), $result); 
    return $result; 
+0

Nie jestem pewien, czy można indeksować jednostkę przy użyciu pola z podmiotu powiązanego. –

+0

Mogę być całkowicie błędny, ale możesz spróbować indeksować według 'product.id' zamiast' p.id'. Ponadto: http://www.doctrine-project.org/jira/browse/DDC-1180 –

+0

ok, product.id nie działa. Twoje odwołanie sugeruje jednak, że poprawka została zaimplementowana, ale nie znalazłem jeszcze odpowiedniego rozwiązania. Czy ty? –

Odpowiedz

4

Atrybut indexBy zastosowanie tylko do podmiotu aktualnie doborem, jak można się domyślić (a AFAIK); więc w twoim przypadku możesz indeksować tylko przez u.id.

To ma dla mnie sens, ponieważ indeksowanie z innego obiektu naprawdę zepsuło zwrócone wyniki. Jedyną sytuacją, w której uzyskasz poprawny wynik, jest:

  • wszystkie sprzężenia od głównej jednostki i "docelowej" jednostki indeksowej są jednostkami jeden do jednego;
  • wszystkie sprzężenia są INNER DOŁĄCZ;
  • kolumna indexBy zestawu wyników jest unikatowa.

W każdym innym przypadku podczas nawilżania traci się referencję do danej instancji.

W twoim przykładzie używasz LEWEGO DOŁĄCZENIA: co stanie się ze wszystkimi obiektami bez produktu? Wszystkie odrzucone, więc LEFT JOIN miałoby pracownika jak INNER JOIN. Ponadto obejście sugeruje, że chcesz łączyć elementy z tym samym indeksem, ale nie jest to sposób działania Doctrine: w Doctrine kolumna indexBy MUSI być unikalna. Aby uzyskać więcej informacji, patrz the official docs.

Zauważ, że możesz indeksować p.id w klauzuli JOIN, ale ma to inne znaczenie. Oznacza to, że podczas nawadniania instancji UserIngredients kolekcja produktu powinna być indeksowana według identyfikatora.

Więc moja propozycja jest taka, aby wykonać jedną z dwóch tego rozwiązania:

  • zrezygnować Doctrine indexBy i wykorzystać swoją workaraound;
  • Jeśli masz odwrotne powiązanie Product -> UserIngredients, użyj Product jako głównej encji zapytania (klauzula "z" i "najpierw" w polu wyboru), a następnie indeksuj według p.id.

Który użyć zależy od logiki biznesowej, ale ja generalnie preferuję drugie rozwiązanie, ponieważ pierwsze generuje tablicę wielopoziomową, która jest lepiej reprezentowana przez relacje encji.

Mam nadzieję, że ta pomoc! :)

+0

dobrze, co ciekawe! w moim przypadku mam wyjątkowe ograniczenia, które gwarantują, że nie ma więcej niż jednego użytkownika w odniesieniu do każdego produktu i użytkownika, więc potrzebujemy indeksować tak, jakbyśmy mieli relację OneToOne, z wyjątkiem tego, że nie jest. Biorąc pod uwagę PR, o którym mówił Jovan, myślę, że słusznie oczekujemy, że da się to zrobić ... wciąż poszukując lepszego rozwiązania. –

+0

Nie sądzę, że DDC-1180 dotyczy twojego problemu. Chodzi o kolumnę podmiotu, która jest również kluczem obcym, więc moje rozważania nadal mają zastosowanie w tej sprawie. W rzeczywistości problem został naprawiony i scalony w Doctrine 2.1, i możesz go teraz użyć. – giosh94mhz

+0

(oops kliknąłeś za szybko) Weź pod uwagę, że nawet jeśli to może być zrobione (ale nie sądzę, że będzie, z powodu wielu warunków wstępnych), nadal nie ma zastosowania do twojej sprawy, ponieważ 'leftJoin' łamie twoją logikę ponieważ nie można mieć wielu wartości związanych z wpisem 'null'-key. – giosh94mhz