2011-10-26 13 views
9

Únete tengo 3 mesasDoctrina 2 de muchos a muchos con tres entidades y una mesa

People 
- id -pk 
- name 

Roles 
- id -pk 
- roleName 

Events 
- id -pk 
- title 

y una tabla de unión

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

un evento tiene muchos papeles. Un rol lo realiza una persona. Una función está asociada a muchos eventos. Una persona puede realizar muchos roles.

Entonces, lo que me gustaría es que cuando obtengo un evento, pueda acceder a una colección de Roles relacionados con ese evento, y de los Roles puedo obtener la Persona que realizó el Rol.

No estoy seguro de cómo voy a hacer para mapear esto en Doctrine 2?

Respuesta

18

Me encontré con este mismo problema hace una semana. Encuesté a los usuarios del canal IRC de Doctrine para encontrar la mejor solución (o al menos la que se practica con mayor frecuencia). Así es como se hace:

Crea una nueva entidad llamada algo así como EventsPeopleRoles con tres propiedades mapeadas mediante @ManyToOne, $ event, $ person y $ role.

Cada asociación debe ser mapeada similar a esto:

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

Luego, en cada una de las tres entidades relacionadas, código del lado inverso de la asociación como esta:

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

A continuación, tiene la elección de agregar una propiedad $ id a su "entidad de unión" o usar una clave primaria compuesta como se describe en here y agregar una anotación de restricción única en la definición de clase de entidad. Tenga en cuenta que las claves externas compuestas solo se admiten a partir de Doctrine 2.1.

Era escéptico sobre esta solución porque no me gusta la idea de crear una entidad solo con el propósito de una unión. Parece como hacer trampa o al menos en contraste con los principios de diseño de ORM. Pero estoy seguro de que esta es la solución aceptada (al menos por ahora) entre los expertos de Doctrine.

+0

Gracias por su respuesta, voy a probar esto y le contaré cómo me llevé. –

+0

Perfecto. ¡Gracias! –

+0

Esto parece funcionar perfectamente para mí también ... ¡Gracias por compartir! – jfgrissom

3

La solución de @ cantera25 es correcta.

Quiero agregar un pensamiento.

Por lo general, si su entidad de unión se unirá a más de dos entidades, eso es una indicación de que tiene un papel bastante importante en su arquitectura de información y debe cambiar de nombre.

Por ejemplo, una aplicación en la que estoy trabajando para una caballeriza tiene una entidad Booking.

Cada Booking tiene al menos un Rider que está montando un Horse para esa reserva.

Originalmente diseñé una entidad llamada BookingRiderHorse, para unir estas tres juntas.

Huelga decir que eso habría sido bastante complicado y difícil de entender más adelante cuando vuelva a visitar el código.

Me cambió el nombre de la antigua entidad Booking-Ride, y se renombró la entidad BookingRiderHorse-Booking.

Ahora bien, en la lógica de negocio, Bookings se crean y debe tener un Ride, Horse y Rider registro existente. Cada Booking tiene solo un Horse y Rider, pero cada Ride puede tener muchos Bookings.

Esto es lo mismo que usar una tabla de unión con un nombre divertido, pero es mucho más fácil de entender y significa que puedo trabajar en la lógica de negocios sin tener que pensar cómo funcionan las uniones.

5

En caso de que alguien es tan novato como yo, simplemente voy a añadir unas anotaciones a esta gran respuesta por @cantera:

En cada una de las tres entidades, hay que añadir el código sugirió, sólo se tenga cuidado de incluir "ORM \" antes de "ManyToOne" y "JoinColumn". También he añadido "@var" anotaciones sólo para aclarar tanto como posible:

en nuestra entidad name = "eventsPeopleRoles", añade la referencia de cada una de las tres entidades:

/** 
* @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; 

En el Nombre de la entidad = "Eventos"

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

En su Entidad name = "Persona"

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

En su Entit y name = "Rol"

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

Cometió un error dentro de la clase de entidad eventsPeopleRoles. En lugar de $ evento privado; al final, es $ rol privado; – kabrice

+0

Gracias Edgar, he reparado mi respuesta. – aleph

Cuestiones relacionadas