2016-01-19 35 views
6

Niedawno opracowałem problem z zapytaniami o tabele łączenia zależności ManyToMany, rozwiązanie było takie samo jak to answer i zastanawiałem się, jak to działa. powiedzmy Mam proste ManyToMany związek między groups i team, nie będzie groups_team tabele, które zostaną automatycznie utworzone tutajW jaki sposób łączenie wewnętrzne działa na relacji wiele do wielu za pomocą Doctrine i Symfony2

podmiot grupy

/** 
* Groups 
* 
* @ORM\Table(name="groups") 
* @ORM\Entity(repositoryClass="AppBundle\Model\Repository\GroupsRepository") 
*/ 
class Groups { 

    /** 
    * @ORM\ManyToMany(targetEntity="Team", inversedBy="group") 
    */ 
    protected $team; 

    public function __construct() { 
     $this->team = new ArrayCollection(); 
    } 

    /** 
    * @var int 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="groupname", type="string", length=255) 
    */ 
    private $groupname; 
    //obligatory getters and setters :) 

podmiotu zespół

/** 
* Team 
* 
* @ORM\Table(name="team") 
* @ORM\Entity(repositoryClass="AppBundle\Model\Repository\TeamRepository") 
*/ 
class Team { 

    /** 
    * @ORM\ManyToMany(targetEntity="Groups", mappedBy="team") 
    */ 
    protected $group; 

    public function __construct(){ 
     $this->group = new ArrayCollection(); 
    } 

    /** 
    * @var int 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="teamname", type="string", length=255) 
    */ 
    private $team; 
    //[setters and getters here] 

w celu aby uzyskać wszystkie zespoły w grupie, musiałbym zapytać o tabelę groups_team table.i bezpośrednio zapytałabym o tabelę tylko w mysql, ale w Symfony mam to zrobić

 $groups = $em->getRepository("AppBundle\Model\Entity\Groups")->findBy(array('tournament' => $tournament->getId())); 

     //get all teams with group id in groups_team table 
     foreach ($groups as $group) { 
      $teamsingroup = $em->getRepository("AppBundle\Model\Entity\Team")->createQueryBuilder('o') 
        ->innerJoin('o.group', 't') 
        ->where('t.id = :group_id') 
        ->setParameter('group_id', $group->getId()) 
        ->getQuery()->getResult(); 
      echo "</b>".$group->getGroupname()."</b></br>"; 
      foreach ($teamsingroup as $teamingroup) { 
       echo $teamingroup->getTeam()."</br>"; 
      } 
     } 

Czy ktoś może mi wyjaśnić, w jaki sposób innerJoin pracuje, a co za tym pojęcia, może kilka dokumentację, aby dowiedzieć się o tym. czy istnieje lepszy sposób na zrobienie tego za pomocą symfony i doktryny.

Odpowiedz

5

Korzystanie ManyToMany między 2 jednostki wiąże się z trzecią tabelę ogólnie nazywane jako stół połączeniowej w tego typu relacji podczas budowania DQL (zapytanie doktryny) doktryna automatycznie dołącza tabelę połączeniową w zależności od charakteru związku, który został określony jako adnotacji tak rozważa zapytanie

$teamsingroup = $em->getRepository("AppBundle\Model\Entity\Team") 
        ->createQueryBuilder('o') 
        ->innerJoin('o.group', 't') 

Jesteś łączenia Team podmiotowi Group podmiotu w innerJoin('o.group') części o jest aliasem dla podmiotu zespołu i o.group odnosi się do mienia określonego w Team podmiotu o nazwie jak group.

/** 
* @ORM\ManyToMany(targetEntity="Groups", mappedBy="team") 
*/ 
protected $group; 

który ma ManyToMany adnotację zdefiniowaną dla tego typu relacji doktryny łączy tabelę zespół pierwszy ze stołem przyłączeniowej, a następnie dołącza tabelę skrzyżowanie z grupy tabeli i otrzymaną SQL będzie coś

SELECT t.* 
FROM teams t 
INNER JOIN junction_table jt ON(t.id = jt.team_id) 
INNER JOIN groups g ON(g.id = jt.group_id) 
WHERE g.id = @group_id 

Kolejna sprawa związana z tym, jak zdobyć zespół dla każdej grupy, możesz zminimalizować swój kod, wykluczając część createQueryBuilder w pętli, po zdefiniowaniu właściwości zespołu jako ArrayCollection.e $this->team = new ArrayCollection(); na każdym obiekcie grupy otrzymasz kolekcje zespołów powiązanych z tą określoną grupą przez wywołanie funkcji getTeam() na obiekcie grupy podobnym do poniższego kodu.

foreach ($groups as $group) { 
    $teamsingroup = $group->getTeam(); 
    echo "</b>".$group->getGroupname()."</b></br>"; 
    foreach ($teamsingroup as $teamingroup) { 
     echo $teamingroup->getTeam()."</br>"; 
    } 
} 
+1

dziękuję, to zmniejszyło mój kod i to zaczęło mnie na drodze do wymyślenia bardziej usprawnionego kodu. To odpowiadało na moje pytanie w 100%. SO to świetna platforma. +1 –

0

Myślę, że jest to dosłownie instrukcja SELECT z INNER JOIN przy użyciu klasy klucz zdefiniowanej klasy encji jako mappedBy lub inversedBy. Dlaczego nie spojrzeć na dziennik doktryny i zobaczyć, co składa się na natywny sql?

How to get Doctrine to log queries in Symfony2 (stackoverflow)

http://vvv.tobiassjosten.net/symfony/logging-doctrine-queries-in-symfony2/ (niektóre przykłady kodu)

nie wiem swoją historię użytkownika za tym, ale słyszałem też, że zaleca się stosowanie jednego do wielu relacji zamiast wielu dla wielu, o ile nie ma do tego silnego powodu, ponieważ większość przypadków może być rozpatrywana przez jednego do wielu poprzez ponowne rozważenie modeli.

+0

Cześć dzięki za odpowiedź, tak, pomyślałem "OneToMany' -' ManyToOne' zamiast 'ManyToMany'. ale, duże, ale bez wątpienia nie to samo, masz "jedną" stronę "OneToMany - ManyToOne", co oznacza, że ​​musimy użyć pętli do wstawienia rekordów, a to nie tylko bałagan, ale także dużo niestandardowego kodu (podpowiedź: wymaga użycia 'clone' lub' detach() '_shivers! _) do wykonania prostej operacji CRUD. i stąd dobry "ManyToMany". –