#doctrine #many-to-many #doctrine-orm
#доктрина #многие ко многим #доктрина-orm
Вопрос:
У меня есть 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?
Ответ №1:
Я столкнулся с этой же проблемой около недели назад. Я опросил пользователей IRC-канала Doctrine в поисках наилучшего решения (или, по крайней мере, наиболее часто применяемого). Вот как это делается:
Создайте новую сущность с именем что-то вроде 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 к вашей «сущности объединения», либо использовать составной первичный ключ, как описано здесь, и добавить уникальную аннотацию ограничения в определение класса сущности . Обратите внимание, что составные внешние ключи поддерживаются только начиная с доктрины 2.1.
Я скептически относился к этому решению, потому что мне не нравится идея создания объекта только для целей объединения. Это похоже на обман или, по крайней мере, противоречит принципам проектирования ORM. Но я уверен, что это принятое решение (по крайней мере, на данный момент) среди экспертов по доктрине.
Комментарии:
1. Спасибо за ваш ответ, я попробую это и дам вам знать, как у меня получилось.
2. Кажется, это тоже отлично работает для меня… Спасибо, что поделились!
Ответ №2:
На случай, если кто-то такой же новичок, как и я, я просто добавлю несколько аннотаций к этому замечательному ответу @cantera:
В каждый из трех объектов вы должны добавить код, который он предложил, только позаботьтесь о том, чтобы «ORM » был включен перед «ManyToOne» и «JoinColumn». Я также добавил аннотации «@var», просто чтобы уточнить, насколько это возможно:
В вашем имени объекта =»eventsPeopleRoles» добавьте ссылку на каждый из трех объектов:
/**
* @var Events $event
*
* @ORMManyToOne(targetEntity="Events", inversedBy="eventsPeopleRoles")
* @ORMJoinColumn(name="event_id", referencedColumnName="id", nullable=false)
*/
private $event;
/**
* @var Events $people
*
* @ORMManyToOne(targetEntity="Person", inversedBy="eventsPeopleRoles")
* @ORMJoinColumn(name="person_id", referencedColumnName="id", nullable=false)
*/
private $people;
/**
* @var Role $role
*
* @ORMManyToOne(targetEntity="Role", inversedBy="eventsPeopleRoles")
* @ORMJoinColumn(name="role_id", referencedColumnName="id", nullable=false)
*/
private $role;
В вашем имени объекта =»События»
/**
* @var ArrayCollection $eventsPeopleRoles
*
* @ORMOneToMany(targetEntity="EventsPeopleRoles", mappedBy="event")
*/
private $eventsPeopleRoles;
В вашем имени объекта =»Person»
/**
* @var ArrayCollection $eventsPeopleRoles
*
* @ORMOneToMany(targetEntity="EventsPeopleRoles", mappedBy="people")
*/
private $eventsPeopleRoles;
В вашем имени объекта =»Роль»
/**
* @var ArrayCollection $eventsPeopleRoles
*
* @ORMOneToMany(targetEntity="EventsPeopleRoles", mappedBy="roles")
*/
private $eventsPeopleRoles;
Комментарии:
1. Вы допустили ошибку внутри класса объектов eventsPeopleRoles. Вместо частного события $; в конце это частная роль $;
2. Спасибо, Эдгар, я исправил свой ответ.
Ответ №3:
решение @cantera25 является правильным.
Я хочу добавить к этому мысль.
Обычно, если ваш объект объединения будет объединять более двух объектов вместе, это указывает на то, что он играет довольно важную роль в вашей информационной архитектуре и должен быть переименован.
Например, приложение, над которым я работаю для конюшни, имеет Booking
объект.
У каждого Booking
есть по крайней мере один Rider
, который использует один Horse
для этого бронирования.
Я изначально разработал объект с именем BookingRiderHorse
, чтобы объединить эти три вместе.
Излишне говорить, что это было бы довольно запутанно и трудно понять позже, когда я вернусь к коду.
Я переименовал прежнюю Booking
сущность в Ride
и переименовал BookingRiderHorse
сущность в Booking
.
Теперь в бизнес-логике Bookings
создаются и должны существовать Ride
Horse
Rider
записи и. У каждого Booking
есть только одно Horse
и Rider
, но у каждого Ride
может быть много Bookings
.
Это то же самое, что использовать таблицу соединений со смешным именем, но ее гораздо проще понять и означает, что я могу работать с бизнес-логикой, не задумываясь о том, как работают соединения.