php - Doctrine 的多对多自引用和互惠

标签 php doctrine-orm doctrine many-to-many

默认情况下,Doctrine 下的自引用 ManyToMany 关系涉及拥有方和相反方,如 documentation 中所述。 .

有没有办法实现双方无差异的互惠关联?

按照文档中的示例:

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

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

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

    // ...
}

因此,将 entity1 添加到 entity2friends 意味着 entity2 将在 entity1的 friend 。

最佳答案

有很多方法可以解决这个问题,都取决于对“ friend ”关系的要求。

单向

一种简单的方法是使用单向多对多关联,并将其视为双向关联(保持双方同步):

/**
 * @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 将被添加到 $userB 中的好友集合中。

这也会导致 2 条记录添加到“ friend ”表中(1,2 和 2,1)。虽然这可以被视为重复数据,但它会大大简化您的代码。例如当你需要查找$userA的所有好友时,你可以简单地这样做:

SELECT u FROM User u JOIN u.friends f WHERE f.id = :userId

无需像使用双向关联那样检查 2 个不同的属性。

双向

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

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

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

OneToMany/ManyToOne

如果您需要一个用户可以添加 friend 的系统,但该 friend 必须确认他们确实是 friend ,您需要将该确认存储在联接表中。然后,您不再有 ManyToMany 关联,而是类似 User <- OneToMany -> Friendship <- ManyToOne -> User 之类的关联。

您可以阅读我关于此主题的博文:

关于php - Doctrine 的多对多自引用和互惠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21244816/

相关文章:

mongodb - 具有 Doctrine mongodb odm 的唯一索引

php - "#"在MySql中代表什么?

Php Sql 获取值

php - 发布数组 foreach 循环上的 "Invalid argument"

php - Symfony2,设置日期时间字段的默认值

php - Symfony 2.7 表单生成器具有来自另一个实体的新字段?

php symfony Doctrine 或从 2 个表中获取数据

php - 在 PHP 中合并两个带有透明胶片的图像

php - 外键约束失败,因为插入语句尚未提交 (MySQL)

symfony - Gedmo Timestampable 和 Blameable 在合并实体后不起作用