2014-06-22 64 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