2014-01-20 17 views
16

默認情況下,自我參照ManyToMany在主義下的關係涉及擁有方和反方,如documentation中所述。主義的多對多的自我參照和互惠

雙方之間有沒有實現互惠聯繫的方法?

繼在文檔的例子:

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

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

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

    // ... 
} 

因此,增加entity1entity2小號friends意味着entity2將在entity1的朋友。

回答

41

有很多方法可以解決這個問題,全部取決於對「朋友」關係的要求。

單向

一個簡單的方法是使用一個單向多對多關聯,並把它當作如果其中一個雙向一個(保持雙方同步):

/** 
* @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個記錄添加到「朋友」表(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)。這使得「查找所有朋友」查詢有點複雜,因爲您必須檢查兩個屬性。

您當然可以通過確保addFriend()將更新$myFriends$friendsWithMe(並保持另一側同步),仍然可以在數據庫中使用2條記錄。這會在你的實體中增加一些複雜性,但查詢變得稍微複雜一些。

一對多/多對一

如果你需要一個系統,用戶可以添加好友,但朋友已證實他們確實是朋友,你需要的是確認存儲在join-表。然後,您不再擁有ManyToMany關聯,但類似User < - OneToMany - >Friendship < - ManyToOne - >User

你可以閱讀我的博客,帖子就這個問題:

+0

單向=>無法確定財產'訪問類型...' – Trix

+0

您需要映射'id'屬性。我已經將它添加到示例中(映射爲整數,但它可以是任何你喜歡的)。 –

+0

非常有用的答案。對我來說,添加的重要部分是'$ user-> addFriend($ this);'。 – StockBreak