Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [Symfony][Doctrine] Zapytania przy relacjach ManyToMany
Forum PHP.pl > Forum > PHP > Frameworki
marekc12
Witam,

pytanie dotyczy Symfony 2.

Wiele książek (tabela book) może być przypisanych do wielu gatunków (tabela genre). Wykorzystałem relację Many-To-Many, Bidirectional.

Wyciągam 20 książek, takich które należą do konkretnego gatunku (po prostu chcę wyświetlić np. tylko książki fantasty), zapytaniem:
  1. $query = $this->getDoctrine()->getRepository('ProjektPageBundle:Book')->createQueryBuilder('b');
  2. $query = $query->join('b.genres', 'g')->where('g.id = gId')->setParameter('gId', $gatunek);
  3. $query = $query->setFirstResult($offset)->setMaxResults(20)->getQuery();
  4. $books = $query->getResult();


wysyłam zmienną $books zawierającą 20 książek do templatki, a w niej wyświetlam je. Przy każdej książce wyświetlam informacje o niej z tabeli book oraz nazwy gatunków do jakich należy dana książka (może być ich kilka). Oto kawałek tamplatki:

  1. {% for book in books %}
  2. <h2>{{ book.title }}, {{ book.titlepl }}</h2>
  3. <p>
  4. Kraj wydania: {{ book.country }}<br />
  5. Gatunki:
  6. {% for genre in book.genres %}
  7. {{ genre.name }}
  8. {% endfor %}
  9. </p>
  10. {% endfor %}


Niby wszystko działa, ale martwi mnie to, że w momencie wyświetlania listy gatunków do których każda książka należy wykonuje się zapytanie do bazy i gdy wyświetlam te 20 książek to dochodzi 20 zapytań. Co oznacza, że pewnie niezbyt dobrze to robię. Jak to powinienem zrobić?

Mam nadzieję, że post jest zrozumiały.
Crozin
Powinieneś jeszcze w zapytaniu zaznaczyć, że chcesz pobrać informacje dot. gatunku: Doctrine\ORM\QueryBuilder::addSelect.
marekc12
  1. ->addSelect('g')


po wciśnięciu tego w zapytanie rzeczywiście dodatkowe zapytania się nie wykonują i gatunki są pobierane od razu razem z książkami, ale teraz niestety widok wyświetla mi przy każdej książce tylko jedną nazwę gatunku ( no bo gatunki są przecież teraz pobierane razem z książkami z tym warunkiem ->where('g.id = gId')-> ). Nie mam pomysłu jak to rozwiązać...
Crozin
Chcesz pobrać książki należące do danego gatunku, więc skorzystaj z MEMBER OF:
  1. SELECT b, g
  2. FROM ProjektPageBundle:Book b
  3. JOIN b.genres g
  4. WHERE :genre MEMBER OF b.genres
Gdzie parametr :genre to obiekt / id danego gatunku.
marekc12
Próbowałem robić coś podobnego wcześniej, Twój sposób rzeczywiście dobrze działa, ale z tym, że teraz nie da się ustawić ilości pobieranych książek, ponieważ, gdy dam ->setMaxResults(20)-> to np. książkę która zawiera 3 gatunki policzy trzykrotnie i w ten sposób pobierze mniej książek niż 20.

Chodzi mi po prostu o podzielenie wyników na wiele stron po 20 wyników.

EDIT:

Wymyśliłem to tak:

  1. SELECT b, g
  2. FROM ProjektPageBundle:Book b
  3. JOIN b.genres g
  4. WHERE b.id IN ( SELECT b2.id FROM ProjektPageBundle:Book b2 WHERE :gId MEMBER OF b2.genres LIMIT 0, 20 )'


być może tak by zadziałało, problemem pozostaje to, że o ile się orientuję to limity są obsługiwane tylko przez ->SetMaxResults(20)->, w każdym razie mam błąd przy słowie LIMIT.

EDIT2:
Chyba trzeba to zapytanie po prostu zapisać w DQB, ale mimo, że znalazłem parę przykładów to dalej nie wiem jak to zrobić.

EDIT 3:

Udało mi się to zamienić na DQB:

  1. $em = $this->getDoctrine()->getEntityManager();
  2.  
  3. $qb = $em->createQueryBuilder();
  4. $qb2 = $em->createQueryBuilder();
  5.  
  6. $qb2->addSelect('b2.id')->from('ProjektPageBundle:Book','b2')->andWhere(':gId MEMBER OF b2.genres');
  7.  
  8. $qb->addSelect('b')->addSelect('g');
  9. $qb->from('ProjektPageBundle:Book','b');
  10. $qb->join('b.genres','g');
  11. $qb->andWhere($qb->expr()->in('b.id', $qb2->getDQL()))->setParameter('gId', array($filter));
  12.  
  13. $query = $qb->getQuery();
  14. $books = $query->getResult();


Ale to nic nie zmienia, ponieważ jeżeli dam setMaxResults to działa on tylko na ostateczną treśc zapytania, czyli na całe zapytanie.

W każdym razie chyba jedynym rozwiązaniem będzie rozdzielenie tego na 2 oddzielnie wykonujące się zapytania. Pierwsze pobierze 20 numerów id książek i da drugiemu żeby wiedziało które książki pobrać.

Dzięki za pomoc, pozdrawiam!
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.