Учение 2 Много ко многим с тремя сущностями и объединяющим столом - PullRequest
11 голосов
/ 26 октября 2011

У меня есть 3 таблицы

People
 - id -pk
 - name

Roles
 - id -pk
 - roleName

Events
 - id -pk
 - title

и таблица соединений

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

Событие имеет много ролей.Роль исполняется человеком.Роль связана со многими событиями.Человек может выполнять много ролей.

Поэтому мне бы хотелось, чтобы при получении события я мог получить доступ к коллекции ролей, связанных с этим событием, а из ролей я мог получить человека, который выполнил роль.

Я не уверен, как бы я сделал это в Doctrine 2?

Ответы [ 3 ]

21 голосов
/ 27 октября 2011

Я столкнулся с той же проблемой около недели назад. Я опросил пользователей канала Doctrine IRC для лучшего решения (или по крайней мере того, которое наиболее часто практикуется). Вот как это делается:

Создайте новый объект с именем что-то вроде EventsPeopleRoles с тремя свойствами, сопоставленными с помощью @ManyToOne, $ event, $ person и $ role.

Каждая ассоциация должна отображаться так:

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

Затем в каждом из трех связанных объектов закодируйте обратную сторону ассоциации следующим образом:

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

Затем у вас есть выбор: либо добавить свойство $ id к вашей «сущности соединения», либо использовать составной первичный ключ, как описано здесь , и добавить уникальную аннотацию ограничения в определении класса сущности. Обратите внимание, что составные внешние ключи поддерживаются только начиная с Doctrine 2.1.

Я скептически отнесся к этому решению, потому что мне не нравится идея создания сущности только для целей объединения. Это похоже на мошенничество или, по крайней мере, в отличие от принципов разработки ORM. Но я уверен, что это является приемлемым решением (пока, по крайней мере) среди экспертов Doctrine.

7 голосов
/ 04 января 2015

Если кто-то такой же новичок, как и я, я просто добавлю несколько аннотаций к этому замечательному ответу @cantera:

В каждую из трех сущностей вы должны добавить предложенный им код, только позаботьтесь о том, чтобы «ORM \» был включен перед «ManyToOne» и «JoinColumn». Я также добавил аннотации "@var", чтобы уточнить как можно больше:

В поле Имя вашей сущности = "eventsPeopleRoles" добавьте ссылку на каждую из трех сущностей:

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

В названии вашей сущности = "События"

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

В вашей сущности имя = "Персона"

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

В названии вашей сущности = "Роль"

/**
 * @var ArrayCollection $eventsPeopleRoles
 *
 * @ORM\OneToMany(targetEntity="EventsPeopleRoles", mappedBy="roles")
 */
private $eventsPeopleRoles;
3 голосов
/ 24 апреля 2012

@ cantera25 - правильное решение.

Я хочу добавить к нему мысль.

Обычно, если ваша объединяемая сущность будет объединять более двух сущностей вместе, это указывает на то, чтоон играет довольно важную роль в вашей информационной архитектуре и должен быть переименован.

Например, приложение, над которым я работаю для конюшен, имеет сущность Booking.

Каждое Booking имеет по крайней мере одного Rider, который едет на одном Horse для этого бронирования.

Я изначально проектировал объект под названием BookingRiderHorse, чтобы объединить эти три.

Само собой разумеется, это было бы довольно беспорядочно и трудно понять позже, когда я вернусь к коду.

Я переименовал прежнюю сущность Booking в Ride и переименовал сущность BookingRiderHorse в Booking.

Теперь в бизнес-логике Bookings созданы и должны иметь существующие записи Ride, Horse и Rider.У каждого Booking есть только один Horse и Rider, но у каждого Ride может быть много Bookings.

Это то же самое, что использование таблицы соединения со смешным именем, но это далеколегче понять и означает, что я могу работать над бизнес-логикой, не думая о том, как работают объединения.

...