默认情况下,Doctrine下的自引用ManyToMany
关系涉及拥有方和反方,如documentation中所述。
有没有办法实现双方之间没有差异的互惠关联?
按照文档中的示例:
<?php
/** @Entity **/
class User
{
// ...
/**
* @ManyToMany(targetEntity="User")
**/
private $friends;
public function __construct() {
$this->friends = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
因此,将entity1
添加到entity2
s friends
意味着entity2
将在entity1
的朋友中。
答案 0 :(得分:49)
有很多方法可以解决这个问题,所有这些都取决于“朋友”关系的要求。
<强>单向强>
一种简单的方法是使用单向ManyToMany关联,并将其视为双向关联(保持双方同步):
/**
* @Entity
*/
class User
{
/**
* @Id
* @Column(type="integer")
*/
private $id;
/**
* @ManyToMany(targetEntity="User")
* @JoinTable(name="friends",
* joinColumns={@JoinColumn(name="user_a_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="user_b_id", referencedColumnName="id")}
* )
* @var \Doctrine\Common\Collections\ArrayCollection
*/
private $friends;
/**
* Constructor.
*/
public function __construct()
{
$this->friends = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* @return array
*/
public function getFriends()
{
return $this->friends->toArray();
}
/**
* @param User $user
* @return void
*/
public function addFriend(User $user)
{
if (!$this->friends->contains($user)) {
$this->friends->add($user);
$user->addFriend($this);
}
}
/**
* @param User $user
* @return void
*/
public function removeFriend(User $user)
{
if ($this->friends->contains($user)) {
$this->friends->removeElement($user);
$user->removeFriend($this);
}
}
// ...
}
当您致电$userA->addFriend($userB)
时,$userB
将被添加到$userA
中的朋友集合中,$userA
将被添加到{{1}中的朋友集合中}}
它还会将2条记录添加到“朋友”表(1,2和2,1)中。虽然这可以看作是重复数据,但它会大大简化您的代码。例如,当您需要找到$userB
的所有朋友时,您可以执行以下操作:
$userA
无需像使用双向关联那样检查2个不同的属性。
<强>双向强>
使用双向关联时,SELECT u FROM User u JOIN u.friends f WHERE f.id = :userId
实体将拥有2个属性,例如User
和$myFriends
。您可以按照与上述相同的方式使它们保持同步。
主要区别在于,在数据库级别上,您只有一条代表关系的记录(1,2或2,1)。这使得“查找所有朋友”查询更加复杂,因为您必须检查这两个属性。
您当然可以在数据库中使用2条记录,确保$friendsWithMe
同时更新addFriend()
和$myFriends
(并保持另一方同步)。这会在您的实体中增加一些复杂性,但查询会变得不那么复杂。
OneToMany / ManyToOne
如果您需要一个系统,用户可以添加朋友,但该朋友必须确认他们确实是朋友,您需要将该确认存储在连接表中。然后,您不再拥有ManyToMany关联,而是$friendsWithMe
&lt; - OneToMany - &gt;之类的关联。 User
&lt; - ManyToOne - &gt; Friendship
。
您可以阅读我关于此主题的博文: