Pregunta

Tengo esta simple situación:

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

Rutina para insertar un nuevo 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

Cómo puedo resolver este problema? Creo que el problema está relacionado con cascadeType.save_update, pero lo necesito ... gracias a todos.


ACTUALIZAR

Encontré el problema y esto es cómo 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);

Entonces, si P y P 1 tiene diferentes categorías, no hay problemas, pero si P y P1 tienen la misma categoría, tengo no uniqueBjectException en la categoría porque la misma categoría está en sesión e hibernate intente salvar_update su.

Necesito cascadeType.save_update en entidades de productos y categorías, entonces, ¿cómo puedo resolver este problema? Gracias.

¿Fue útil?

Solución

El problema probablemente se deba a la mala gestión de transacciones. Todo su código debe hacerse en una sola transacción, en lugar de tener una transacción para cada llamada DAO. La capa de servicio debe ser la que demarga la transacción, y no la capa DAO.

Puedo imaginar lo que Hibernate hace:

  1. Llama dao.get(Product.class, 2). Esto devuelve un producto separado que apunta a la categoría con ID 67 (por ejemplo). El resultado se separa porque la transacción termina cuando termina la llamada al DAO.
  2. Llama dao.get(Product.class, 3). Esto devuelve un producto separado que apunta a la categoría con ID 67 (por ejemplo). Pero dado que la llamada se ejecuta en otra transacción, obtienes una segunda instancia de categoría diferente (con la misma ID que la primera).
  3. Llamas a SaveorUpdate en el producto. Esto cae en cascada a la categoría, y Hibernate debe adjuntar la categoría 1 y la categoría 2 a la sesión. Como ambos tienen la misma identificación, una de las cascadas no se puede hacer.

Si usa una sola transacción para obtener ambos productos, ambos tendrán la misma instancia de categoría y el problema no ocurrirá. Vocación merge en vez de saveOrUpdate También debe funcionar: Hibernate copiará el estado de ambas categorías a una tercera, adjunta. Pero lo correcto es usar una transacción que involucra ambas llamadas al DAO.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top