2011-10-26 10 views
9

Ho 3 tabelleDoctrine 2 molti a molti con tre entità e un join tabella

People 
- id -pk 
- name 

Roles 
- id -pk 
- roleName 

Events 
- id -pk 
- title 

e un join tavolo

event_performers 
- event_id -pk 
- role_id -pk 
- people_id -pk 

un evento ha molti ruoli. Un ruolo è eseguito da una persona. Un ruolo è associato a molti eventi. Una persona può eseguire molti ruoli.

Quindi quello che vorrei è che quando ottengo un evento posso accedere a una raccolta di ruoli relativi a quell'evento, e dai ruoli posso ottenere la persona che ha eseguito il ruolo.

Non sono sicuro di come fare per mappare questo in Doctrine 2?

risposta

18

Mi sono imbattuto in questo stesso problema circa una settimana fa. Ho interrogato gli utenti del canale IRC Doctrine per la soluzione migliore (o almeno quella più comunemente praticata). Ecco come si fa:

Creare una nuova entità denominata qualcosa come EventsPeopleRoles con tre proprietà mappata utilizzando @ManyToOne, $ evento, $ persona, e $ ruolo.

Ogni associazione deve essere mappato simile a questo:

/** 
* @ManyToOne(targetEntity="Events", inversedBy="eventsPeopleRoles") 
* @JoinColumn(name="event_id", referencedColumnName="id", nullable=false) 
*/ 
private $event; 

Poi in ciascuna delle tre entità correlate, il codice lato inverso della associazione in questo modo:

/** 
* @OneToMany(targetEntity="EventsPeopleRoles", mappedBy="event") 
*/ 
private $eventsPeopleRoles; 

quindi si ha la possibilità di aggiungere una proprietà $ id alla "join entity" o utilizzare una chiave primaria composta come descritto here e aggiungere un'annotazione di vincolo univoco nella definizione della classe di entità. Nota che le chiavi esterne composte sono supportate solo a partire da Doctrine 2.1.

Ero scettico su questa soluzione perché non mi piace l'idea di creare un'entità solo ai fini di un join. Sembra imbrogliare o almeno in contrasto con i principi di progettazione ORM. Ma sono fiducioso che questa sia la soluzione accettata (almeno per ora) tra gli esperti di Doctrine.

+0

Grazie per la tua risposta, ci proverò e ti farò sapere come sono arrivato. –

+0

Perfetto. Grazie! –

+0

Questo sembra funzionare perfettamente anche per me ... Grazie per aver condiviso! – jfgrissom

3

La soluzione di @ cantera25 è giusta.

Voglio aggiungere un pensiero ad esso.

In genere, se l'entità di join si unirà a più di due entità insieme, ciò indica che ha un ruolo piuttosto importante nell'architettura delle informazioni e deve essere rinominato.

Ad esempio, un'applicazione a cui sto lavorando per un maneggio ha un'entità Booking.

Ogni Booking ha almeno uno Rider che sta guidando uno Horse per quella prenotazione.

Originariamente ho progettato un'entità denominata BookingRiderHorse, per unire questi tre insieme.

Inutile dire che sarebbe stato piuttosto complicato e difficile da capire in seguito quando ho rivisitato il codice.

Ho rinominato la precedente entità Booking in Ride e rinominato l'entità BookingRiderHorse in Booking.

Ora, nella logica di business, Bookings sono creati e deve ricevere una Ride, Horse e Rider record esistente. Ogni Booking ha solo uno Horse e Rider, ma ogni Ride può avere molti Bookings.

È come utilizzare una tabella di join con un nome divertente, ma è molto più semplice da comprendere e significa che posso lavorare sulla logica di business senza dover pensare a come funzionano i join.

5

Nel caso in cui qualcuno è come novizio come me, mi limiterò a aggiungere alcune annotazioni a questa grande risposta da @cantera:

In ciascuna delle tre entità, si deve aggiungere il codice ha suggerito, solo fare attenzione che "ORM \" deve essere incluso prima di "ManyToOne" e "JoinColumn". Ho anche aggiunto "@var" annotazioni solo per chiarire quanto posible:

In vostra entità name = "eventsPeopleRoles", aggiungere il riferimento di ciascuna delle tre entità:

/** 
* @var Events $event 
* 
* @ORM\ManyToOne(targetEntity="Events", inversedBy="eventsPeopleRoles") 
* @ORM\JoinColumn(name="event_id", referencedColumnName="id", nullable=false) 
*/ 
private $event; 

/** 
* @var Events $people 
* 
* @ORM\ManyToOne(targetEntity="Person", inversedBy="eventsPeopleRoles") 
* @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false) 
*/ 
private $people; 

/** 
* @var Role $role 
* 
* @ORM\ManyToOne(targetEntity="Role", inversedBy="eventsPeopleRoles") 
* @ORM\JoinColumn(name="role_id", referencedColumnName="id", nullable=false) 
*/ 
private $role; 

Nel tuo nome Entity = "Eventi"

/** 
* @var ArrayCollection $eventsPeopleRoles 
* 
* @ORM\OneToMany(targetEntity="EventsPeopleRoles", mappedBy="event") 
*/ 
private $eventsPeopleRoles; 

Nella tua Entity name = "persona"

/** 
* @var ArrayCollection $eventsPeopleRoles 
* 
* @ORM\OneToMany(targetEntity="EventsPeopleRoles", mappedBy="people") 
*/ 
private $eventsPeopleRoles; 

Nella tua Entit y name = "Ruolo"

/** 
* @var ArrayCollection $eventsPeopleRoles 
* 
* @ORM\OneToMany(targetEntity="EventsPeopleRoles", mappedBy="roles") 
*/ 
private $eventsPeopleRoles; 
+0

Hai commesso un errore nella classe di entità eventsPeopleRoles. Invece di $ $ evento privato; alla fine, è un ruolo privato $; – kabrice

+0

Grazie Edgar, ho risolto la mia risposta. – aleph