教义的多对多自我引用和互惠

alb*_*igo 18 php doctrine many-to-many doctrine-orm

默认情况下,ManyToManyDoctrine 下的自引用关系涉及拥有方和反方,如文档中所述.

有没有办法实现双方之间没有差异的互惠协会?

按照文档中的示例:

<?php
/** @Entity **/
class User
{
    // ...

    /**
     * @ManyToMany(targetEntity="User")
     **/
    private $friends;

    public function __construct() {
        $this->friends = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

因此,加入entity1entity2小号friends 意味着entity2会在entity1朋友.

Jas*_*wer 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);
        }
    }

    // ...

}
Run Code Online (Sandbox Code Playgroud)

当你打电话时$userA->addFriend($userB),$userB会被添加到friends-collection中$userA,$userA并将被添加到friends-collection中$userB.

它还会将2条记录添加到"朋友"表(1,2和2,1)中.虽然这可以看作是重复数据,但它会大大简化您的代码.例如,当你需要找到所有的朋友时$userA,你可以简单地做:

SELECT u FROM User u JOIN u.friends f WHERE f.id = :userId
Run Code Online (Sandbox Code Playgroud)

无需检查2个不同的属性,就像使用双向关联一样.

双向

当使用双向关联的User实体将具有2个属性,$myFriends$friendsWithMe例如.您可以按照与上述相同的方式使它们保持同步.

主要区别在于,在数据库级别上,您只有一条记录代表关系(1,2或2,1).这使得"查找所有朋友"查询更加复杂,因为您必须检查这两个属性.

你当然可以仍然使用2条记录在数据库中,确保addFriend()将同时更新$myFriends$friendsWithMe(并保持另一侧同步).这将在您的实体中增加一些复杂性,但查询变得不那么复杂.

OneToMany/ManyToOne

如果您需要一个系统,用户可以添加朋友,但该朋友必须确认他们确实是朋友,您需要将该确认存储在连接表中.然后你不再拥有ManyToMany关联,而是像User< - OneToMany - > Friendship< - ManyToOne - > User.

你可以阅读我关于这个主题的博客文章: