2014-06-22 108 views
4

是否有任何解決方案,自動做到這一點?更新許多-to-many關聯doctrine2

我的兩個實體:

class User 
{ 
    /* * 
    * @ManyToMany(targetEntity="Product", inversedBy="users") 
    * @JoinTable(name="user_product", 
    * joinColumns={@JoinColumn(name="user_id", referencedColumnName="idUser")}, 
    * inverseJoinColumns={@JoinColumn(name="product_id", referencedColumnName="idProduct")} 
    * 
    *) 
    */ 
protected $products; 
} 

class Product { 
    /** 
    * @ManyToMany(targetEntity="User", mappedBy="products") 
    */ 
protected $users; 
} 

用戶實體有兩個產品存在已經相關ID(12):

$user = $entityManager->find('User', 1); 

此數組來自視圖與新產品要插入,刪除的數據或已經在列表中的任何內容:

$array = array(1, 3, 4); 

在這種情況下:

1 = Already in association with User (do nothing) 
2 = not in array and should be deleted 
3 = should be inserted 
4 = should be inserted 

如何做到這一點的doctrine2?有沒有一個合併功能自動執行或手動執行?

+0

**答案**:請參考我在http://stackoverflow.com/a/35445060/2423563 – SudarP

回答

7

考慮下面的代碼

$user = $entityManager->find('User', 1); 
$products = array(); 

foreach(array(1, 3, 4) as $product_id) { 
    $products[$product_id] = $entityManager->getReference('MyBundle\Entity\Product', $product_id); 
} 

$user->setProducts($products);  
$entityManager->persist($user); 
$entityManager->flush(); 

而且setProducts定義爲

function setProducts($products) { 
    $this->products = new ArrayCollection($products); 
} 

在這種情況下學說將刪除所有用戶的產品的關聯,然後再插入每個產品的關聯從視圖傳遞英寸

我在我的系統上測試了這個,其中visit實體與許多visit_tag實體關聯。請注意,doctrine會刪除下面的profiler屏幕截圖中給定visit對象的所有visit_tag關聯,然後創建每個關聯。

enter image description here

爲了有學說只刪除/插入協會根據需要,你必須手動合併現有$user->products ArrayCollection而不是重寫它像上面的。您可以使用indexed associations通過indexBy批註高效地執行此操作,該批註允許您在固定時間內通過唯一密鑰(即產品ID)搜索/添加/移除關聯。

class User 
{ 
    /** 
    * @ManyToMany(targetEntity="Product", inversedBy="users", indexBy="id") 
    * @JoinTable(name="user_product", 
    * joinColumns={@JoinColumn(name="user_id", referencedColumnName="idUser")}, 
    * inverseJoinColumns={@JoinColumn(name="product_id", referencedColumnName="idProduct")} 
    *) 
    */ 
    protected $products; 

    public function setProducts($products) { 
     foreach($this->products as $id => $product) { 
      if(!isset($products[$id])) { 
       //remove from old because it doesn't exist in new 
       $this->products->remove($id); 
      } 
      else { 
       //the product already exists do not overwrite 
       unset($products[$id]); 
      } 
     } 

     //add products that exist in new but not in old 
     foreach($products as $id => $product) { 
      $this->products[$id] = $product; 
     }  
    } 
} 

現在,事件探查器顯示該規則只會刪除特定的關聯(而不是全部),並且只會插入新的關聯。

enter image description here

然而,爲了做手工合併學說查詢所有協會,你不會有不這樣做的分貝。簡而言之:

方法1

  1. 刪除所有關聯
  2. 插入從視圖中傳遞

方法2

  1. 所有關聯選擇的所有關聯
  2. 刪除只有那些做n的協會OT存在了
  3. 從插入之前

方法2是更好,當協會的#改爲相比,聯想的總#是比較小的是不存在的觀點僅這些關聯。但是,如果您要改變大多數關聯,則方法1似乎是要走的路。

+0

上所做的回答謝謝,它是一種想要的。我認爲核心原則2有好處,你怎麼看? – gustavomr

+0

你用什麼工具看到這個查詢正在運行? – gustavomr

+0

@gustavomr symfony的個人資料 – FuzzyTree