Doctrine ManyToMany relationship, not desired associations

Sa zicem ca am urmatorele 3 entitati: User, Movie, Comment.
Intre User si Movie e o relatie ManyToMany. iar intre User si Comment e o relatie OneToMany.
Am nevoie ca sa obtin, toti utilizatorii unui film, cu comentariile lor.
Daca fac asa:

{% for movie in movies %}
  {% for user in movie.users %}
    {{ user.comments }}
  {% endfor %}
{% endfor }

Problema e ca {{ user.comments }} imi afiseaza mai multe date decat ar trebui, deoarece, in spate, se face un query de genul:
SELECT * FROM comments WHERE user_id = x

Dar trebuie de luat in calcul faptul ca user-ul x are comentarii si de la alte filme, dar mie imi trebuie doar pentru filmul respectiv, adica sa tina cont de chainning-ul asta: movie -> users -> comments.
In Laravel, cu Eloquent, trebuia asta functiona bine, by default. Aici in Doctrine vad ca e altfel.
Cum as putea rezolva problema?
Multumesc.

1 Like

Nu m-am jucat prea mult cu Symfony, deci s-ar putea sa spun prostii.
Cum ai definite entitatile (Entity) si relatiile? Poti sa dai copy paste la cod? De asemenea cum iei movies in controller?

Ar trebui să ai datele pregătite deja în controller în mod corect; adaugă query-ul Doctrine folosit pentru extragerea datelor.

Mie personal relația între entități mi se pare ciudată (nu stiu care e use case-ul tau) dar ași folosi ceva de genul:

User —> UserMovieComment <— Movie

unde

UserMovieComment ar contine userId si movieId.

1 Like

eu nu inteleg de ce trebuie sa fie o relatie intre movie si user. normal ar fi user has many comments, comment belongs to user/movie, movie has many comments.

Si eu sunt de parere ca structura este gresita. Structura la care ma gandesc ar fi:

User has many Comments
Movie has many Comments
Comment created by User

Movie > Comments > User (legat de comments printr-o proprietate createdBy).

Si in felul asta ca sa obtii ce vrei iei Movie cu toate comentariile si la fiecare comentariu ai putea afisa de cine este creat si astfel iese si un singur foreach.

Nici nu iti trebuie query builder ai aici exemplu cum e optim: http://symfony.com/doc/current/doctrine.html#fetching-objects-from-the-database

1 Like

De ce am nevoie de o relatie ManyToMany intre Movie si User? Sa presupunem ca User ar fi un actor al filmului, ca sa fie mai clar. Un Movie poate avea mai multi actori, iar un actor poate face parte din mai multe filme. Daca tot nu e clar nici asa, atunci renunt la analogie, si va dau exemplul meu concret. Am 3 entitati: Report, Query, Issue. Asocierile care le-am facut, sunt in felul urmator: Movie = Report, Query = User, Comment = Issue.
Deci intre Report si Query trebuie sa fie o relatie ManyToMany deoarece, un Report poate contine mai multe Query-uri, iar un Query poate fi folosit in mai multe Report-uri. Intre Query si Issue, e relatie OneToMany, pentru ca un Query poate avea mai multe issues.
Pe mine ma intereseaza sa extrag Report -> queries -> issues, deci un raport impreuna cu query-urile lui, iar pentru fiecare dintre aceste query-uri, sa fie si issue-urile care au fost gasite in urma acelui Query, dar sa fie issue-urile doar de la raportul respectiv.

Ai putea să încerci să filtrezi colectia respectivă, folosind un anumit criteriu. Eu spre exemplu îmi fac cate un getter care îmi dă colecții filtrate pentru diverse situații. Mai multe detalii aici: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#filtering-collections

Prima remarca ar fi folosirea termenului “user”. E un cuvant prea generic, eu mereu insist pe folosirea unui cuvant specific. Deci daca in cazul tau user este un actor, de ce sa nu folosesti Actor? :smile:

De ce nu iti faci o metoda de business in care sa obtii exact datele pe care le vrei, fara sa te lasi “pe seama” magiei doctrine șcl? Concret, eu as avea un serviciu care sa imi dea date despre raport,

// declarat ca serviciu in containerul de Symf,
// sa zicem la cheia 'reports.repository'
class ReportsRepository 
{

  public function extended()
  {
    // aici apelezi ce vrei tu din doctrine sa-ti dea datele, ideal faci tu SQLul optimizat de care ai nevoie
    return $collection;
  }

}

iar in controller apelezi doar

$reports = $this->get('reports.repository')->extended();

si il pasezi la view si gata.

2 Likes