Aggiorna l'associazione many-to-many doctrine2

C'è qualche soluzione per farlo automaticamente?

Le mie due entity framework;:

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

L' entity framework; utente esiste con due ID di prodotti già associati ( 1 , 2 ):

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

Questo arrays è venuto dalla vista con i nuovi dati dei prodotti da inserire, cancellati o se già nella list non fare nulla:

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

In questo caso:

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

Come fare questo in doctrine2? C'è una function di unione che lo fa automaticamente o shoud? Lo faccio manualmente?

Considera il seguente codice

 $user = $entityManager->find('User', 1); $products = arrays(); foreach(arrays(1, 3, 4) as $product_id) { $products[$product_id] = $entityManager->getReference('MyBundle\Entity\Product', $product_id); } $user->setProducts($products); $entityManager->persist($user); $entityManager->flush(); 

E setProducts definito come

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

In questo caso, doctrine cancellerà tutte le associazioni di prodotto dell'utente e quindi inserirà each associazione di prodotto passata dalla vista.

Ho provato questo sul mio sistema in cui un'entity framework; visit è associata a molte entity framework; visit_tag . Nota che la visit_tag cancella tutte visit_tag associazioni visit_tag per un dato object visit nello screenshot del profiler qui sotto e poi crea ognuna.

inserisci la descrizione dell'immagine qui

Per fare in modo che la doctrine elimini / inserisca solo associazioni come necessario, devi unire manualmente i $user->products ArrayCollection esistenti invece di sovrascriverli come sopra. E puoi farlo in modo efficiente usando le associazioni indicizzate tramite l'annotazione indexBy , che ti permette di cercare / aggiungere / rimuovere associazioni con una chiave univoca (cioè id prodotto) in tempo costante.

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

Ora il profiler mostra che la doctrine elimina solo associazioni specifiche (invece di tutte) e inserisce solo nuove associazioni.

inserisci la descrizione dell'immagine qui

Tuttavia, per fare il manuale unire doctrine interroga il db per tutte le associazioni, che non dovresti fare altrimenti. In poche parole:

Metodo 1

  1. Elimina tutte le associazioni
  2. Inserisci tutte le associazioni passate dalla vista

Metodo 2

  1. Seleziona tutte le associazioni
  2. Elimina solo quelle associazioni che non esistono più
  3. Inserisci solo quelle associazioni dalla vista che non esisteva prima

Il metodo 2 è migliore quando il numero di associazioni modificate è relativamente piccolo rispetto al numero totale di associazioni. Tuttavia, se stai modificando la maggior parte delle tue associazioni, il Metodo 1 sembra essere la strada da percorrere.