主义2多对多有三个实体和连接表

时间:2011-10-26 14:03:31

标签: doctrine many-to-many doctrine-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

一个事件有很多角色。 角色由人员执行。 角色与许多事件相关联。 一个人可以执行许多角色。

所以我想要的是,当我收到一个事件时,我可以访问与该事件相关的角色集合,并且从角色中我可以获得执行该角色的人员。

我不确定如何在Doctrine 2中进行映射?

3 个答案:

答案 0 :(得分:21)

一周前我遇到了同样的问题。我对Doctrine IRC频道用户进行了调查,以获得最佳解决方案(或者至少是最常用的解决方案)。以下是它的完成方式:

使用@ManyToOne,$ event,$ person和$ role创建一个名为EventsPeopleRoles的新实体,其中包含三个属性。

每个关联的映射应与此类似:

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

然后在三个相关实体的每一个中,编码关联的反面,如下所示:

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

然后,您可以选择将“$ id”属性添加到“join实体”,或者使用复合主键(如here所述)并在实体类定义中添加唯一约束注释。请注意,仅在Doctrine 2.1中支持复合外键。

我对此解决方案持怀疑态度,因为我不喜欢仅为了加入而创建实体的想法。这似乎是作弊或至少与ORM设计原则相反。但我相信这是学说专家中公认的解决方案(至少目前为止)。

答案 1 :(得分:7)

如果有人像我一样是新手,我会在@cantera中为这个伟大的答案添加一些注释:

在这三个实体的每个实体中,你必须添加他建议的代码,只需要注意" ORM \"必须包括在" ManyToOne"和#34; JoinColumn"。我还添加了#34; @ 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;

答案 2 :(得分:3)

@ cantera25的解决方案是正确的。

我想为它添加一个想法。

通常情况下,如果您的加入实体将加入两个以上的实体,则表明它在您的信息架构中具有相当重要的作用,应该重命名。

例如,我正在为骑马马厩工作的应用程序有一个Booking实体。

每个Booking至少有一个RiderHorse一起预订。{/ p>

我最初设计了一个名为BookingRiderHorse的实体,将这三个实体加在一起。

毋庸置疑,当我重新审视代码时,这将是非常混乱和难以理解的。

我将以前的Booking实体重命名为Ride,并将BookingRiderHorse实体重命名为Booking

现在,在业务逻辑中,Bookings已创建,且必须具有现有的RideHorseRider记录。每个Booking只有一个HorseRider,但每个Ride可以有多个Bookings

这与使用具有有趣名称的连接表相同,但更容易理解,这意味着我可以处理业务逻辑而无需考虑连接的工作方式。