更新多对多关联原则2 [英] Update many-to-many association doctrine2

查看:149
本文介绍了更新多对多关联原则2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法自动执行?



我的两个实体:

  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)
* /
保护$用户;
}

用户实体存在两个产品已经关联的ids( 1 2 ):

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

此数组来自视图,新的产品数据将被插入,删除或者如果已经在列表中不执行任何操作:

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

在这种情况下:

  1 =已经与用户关联(不做任何事)
2 =不在数组中,应该被删除
3 =应该插入
4 =应该插入

如何在doctrine2中执行此操作?有没有一个合并功能自动执行或者手动执行?

解决方案

考虑以下代码

  $ 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_tag 实体。请注意,在下面的剖析器截图中,doctrine会删除给定访问对象的所有 visit_tag 关联,然后创建每个



为了使教条只能根据需要删除/插入关联,您必须手动合并现有的 $ user->产品ArrayCollection 而不是覆盖它像上面。您可以使用索引关联通过 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])){
//从旧版本中删除,因为它不存在于新的
$ this-> products-> remove($ id);
}
else {
//产品已存在不覆盖
unset($ products [$ id]);
}
}

//添加新的但不在旧的
foreach中的产品($ products as $ id => $ product){
$ this-> products [$ id] = $ product;
}
}
}

现在剖析器显示了这个原则只删除特定关联(而不是全部),并且仅插入新的关联。





但是,为了做手工合并原则,查询所有关联的数据库,否则不需要这样做。简单来说:



方法1


  1. 删除所有关联

  2. 插入从视图中传入的所有关联

方法2


  1. 选择所有关联

  2. 仅删除那些不存在的关联

  3. 仅插入那些关联在

之前不存在的视图在更改的关联数相对于总共的关联数相对较小时更好。但是,如果您正在更改大部分的关联,方法1似乎是要走的路。


Is there any solution to do this automatically?

My two entities:

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;
}

User entity exists with two Products already associated ids (1, 2):

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

This array came from view with new Products data to be inserted, deleted or if already in list do nothing:

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

In this case:

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

How to do this in doctrine2? Is there a merge function that do it automatically or shoud I do it manually?

解决方案

Consider the following code

$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();

And setProducts defined as

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

In this case doctrine will delete all the user's product associations and then insert each product association passed in from the view.

I tested this on my system where a visit entity is associated to many visit_tag entities. Note that doctrine deletes all visit_tag associations for a given visit object in profiler screenshot below and then creates each one.

In order to have doctrine only delete/insert associations as needed, you have to manually merge the existing $user->products ArrayCollection instead of overwriting it like above. And you can do this efficiently using indexed associations via the indexBy annotation, which lets you search/add/remove associations by a unique key (i.e. product id) in constant time.

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;
        }    
    }
}

Now the profiler shows that doctrine only deletes specific associations (instead of all) and only inserts new associations.

However, in order to do the manual merge doctrine queries the db for all associations, which you would not have to do otherwise. In a nutshell:

Method 1

  1. Delete all associations
  2. Insert all associations passed in from view

Method 2

  1. Select all associations
  2. Delete only those associations that do not exist anymore
  3. Insert only those associations from the view that did not exist before

Method 2 is better when the # of associations changed is relatively small compared to the total # of associations. However if you're changing most of your associations, Method 1 seems to be the way to go.

这篇关于更新多对多关联原则2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆