Estoy tratando de hacer una copia de una entidad de hibernación A como esta:
A a = (A) session.get(A.class, id); session.evict(a); a.setId(null); session.save(a);Sin embargo, esto no funciona y obtengo la siguiente experiencia:
org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": com.test.ABEs seguro asumir que este error ocurre porque tengo una colección de entidades B definidas en la entidad A:
<list name="B" table="B" lazy="false" cascade="all,delete-orphan"> <key column="A_ID" not-null="true"/> <index column="X"/> <one-to-many class="com.test.B"/> </list>¿Cómo es posible hacer una copia de la entidad A, incluida su colección de entidades B sin que Hibernate esté descontento con eso?
Si desea copiar una entidad existente, modificarla y guardarla como una nueva entidad, debe realizar una copia profunda de ese objeto. Puede hacer una copia profunda de un objeto serializando y luego deserializando ese objeto.
public Object deepCopy(Object input) { Object output = null; try { // Writes the object ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(input); // Reads the object ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); output = objectInputStream.readObject(); } catch (Exception e) { e.printStackTrace(); } return output; }Tuve el mismo problema anteriormente en mi proyecto.
Para mí funciona, establecer la ID de las entradas de la lista en nulo.
// make copy a of aOriginal by using serialisation clone a.setId(null); for (B b : a.getBs()) { b.setId(null); } session.save(a);Para el clon en sí, utilicé el clon de Apache SerializationUtils .
La razón es que hibernate intenta "reutilizar" las entradas de la lista ya persistentes para la entidad "copiada". Pero estas entradas de lista ya persistentes están vinculadas a una entidad original. Entonces intenta "cambiar" la lista en sí misma en la entidad, porque la entidad cambió. Pero no puede cambiar la lista si está anotada con "eliminar huérfanos" (solo puede modificar las entradas de la lista, pero no la lista en sí). Así que se lanza la excepción.
Si configuro los ID de entrada de lista en nulo, también se insertarán newley. Y la jerarquía de objetos (en lugar de solo la entidad principal) se duplica. Entonces la excepción ya no se lanza.
No hay una forma automática de copiar objetos como ese. En general, el objeto copiado podría estar asociado con otros objetos que están más asociados con otros objetos, etc., por lo que podría terminar copiando una gran parte de la base de datos. Cualquier herramienta que utilice para copiar debe saber en qué parte del gráfico de objetos debe dejar de copiar, qué no copiar (en términos de entidades de Hibernate, son ids, columnas de versión y similares), etc.
Sin embargo, puede utilizar marcos como Dozer para evitar la mayor parte del código repetitivo que necesitaría escribir manualmente.
Con respecto al problema de la reasignación de la colección, no puede tener la misma colección de instancias B asignadas a dos A diferentes, ya que lógicamente sería una asociación many-to-many . También es algo de lo que debería encargarse manualmente, ya que es específico para el caso de uso de su negocio.
Además, asegúrese de no reutilizar los mismos proxies de colección de una instancia de entidad en otras, ya que Hibernate los vincula a sus padres originales internamente; siempre cree una nueva colección en nuevas instancias (que pueden o no contener los mismos elementos).