Доктрина 2 многие ко многим с тремя сущностями и таблицей объединения

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

People
 - id -pk
 - name

Roles
 - id -pk
 - roleName

Events
 - id -pk
 - title

и присоединить таблицу

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

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

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

Я не уверен, как я бы пошел о отображении этого в доктрине 2 ?

3 ответов


я столкнулся с этой же проблемой неделю назад. Я опросил пользователей канала 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 к вашей "сущности join", либо использовать составной первичный ключ, как описано здесь и добавление уникальной аннотации ограничения в определение класса сущностей. Обратите внимание, что составные внешние ключи поддерживаются только начиная с доктрины 2.1.

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


если кто-то такой же Новичок, как и я, я просто добавлю несколько аннотаций к этому замечательному ответу @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;

@cantera25 прямо.

я хочу добавить к этому мысль.

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

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

каждого Booking есть по крайней мере один Rider кто едет один Horse за это бронирование.

я первоначально разработал сущность под названием BookingRiderHorse, чтобы соединить эти три вместе.

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

я переименовал бывший Booking сущности Ride и переименовано в BookingRiderHorse сущности Booking.

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

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