Domanda

Ho questa semplice situazione:

@Entity
public class Customer{

    @ManyToMany(fetch=FetchType.EAGER)
    @Cascade(CascadeType.SAVE_UPDATE)
    private List<Product> products=new ArrayList<Product>();

}

@Entity
public class Produtc{

    @ManyToOne
    @Cascade(CascadeType.SAVE_UPDATE)
    private Category category;
}

@Entity
public class Category{

    private String name;
}

Routine per inserire un nuovo cliente:

Customer customer=new Customer();
//customer.set data
Product p=dao.getProductBySomeUserInput...
if(p==null){
   p=new Product();
   //p.set data
}
customer.addProduct(p);
dao.save(customer);  //this row throw NonUniqueObjectException on Category class

Come posso risolvere questo problema? Penso che il problema sia legato a cascadetype.save_update, ma ne ho bisogno ... grazie a tutti.


AGGIORNARE

Ho trovato il problema e questo è come replicarlo:

Customer c=new Customer();
// Load two products by id
Product p=dao.get(Product.class, 2);
Product p1=dao.get(Product.class, 3);
c.addProduct(p);
c.addProduct(p1);
// This try to update products, and category of products becouse CascadeType is SAVE_UDPATE
dao.save(c);

Quindi, se P e P 1 hanno categorie diverse non ci sono problemi, ma se P e P1 hanno la stessa categoria, ho non UniqueObjectException nella categoria perché la stessa categoria è in sessione e Hibernate prova a salvare_update.

Ho bisogno di cascadetype.save_update in entrambe le entità di prodotto e categoria, quindi come posso risolvere questo problema? Grazie.

È stato utile?

Soluzione

Il problema è probabilmente dovuto alla cattiva gestione delle transazioni. Tutto il codice dovrebbe essere eseguito in una singola transazione, anziché avere una transazione per ogni chiamata DAO. Il livello di servizio dovrebbe essere quello che demarca la transazione e non il livello DAO.

Posso immaginare cosa fa Hibernate:

  1. Chiami dao.get(Product.class, 2). Ciò restituisce un prodotto indipendente che punta alla categoria con ID 67 (ad esempio). Il risultato è staccato perché la transazione termina quando la chiamata al DAO termina.
  2. Chiami dao.get(Product.class, 3). Ciò restituisce un prodotto indipendente che punta alla categoria con ID 67 (ad esempio). Ma poiché la chiamata esegue in un'altra transazione, ottieni una seconda, diversa istanza di categoria (con lo stesso ID della prima).
  3. Chiami SaveorUpdate sul prodotto. Questo cascata alla categoria e Hibernate deve quindi allegare la categoria 1 e la categoria2 alla sessione. Dal momento che entrambi hanno lo stesso ID, una delle cascate potrebbe non essere fatta.

Se si utilizza una singola transazione per ottenere entrambi i prodotti, entrambi avranno la stessa istanza di categoria e il problema non si verificherà. Chiamata merge invece di saveOrUpdate Dovrebbe anche funzionare: Hibernate copierà lo stato di entrambe le categorie a un terzo, allegato. Ma la cosa giusta da fare è usare una transazione che coinvolge entrambe le chiamate al DAO.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top