2010-01-14 15 views
13

tengo estas entidadesHibernate - borrar una colección con todo-delete-orphan y luego añadiendo a la misma causa ConstraintViolationException

class Foo{ 
    Set<Bar> bars; 
} 

class Bar{ 
    Foo parent; 
    String localIdentifier; 
} 

Con esta asignación (lo siento, no hay anotaciones, estoy pasado de moda):

<class name="Foo"> 
    ... 
    <set name="bars" cascade="all-delete-orphan" lazy="false" inverse="true"> 
     <key>...</key> 
     <one-to-many class="Bar"/> 
    </set> 
</class> 


<class name="Bar"> 
    ... 
    <property name="localIdentifier" column="local_identifier"/> 
    <many-to-one name="parent" column="parent_id" /> 
</class> 

I también tienen una restricción única en 2 columnas: local_identifier y parent_id (no una restricción único en cada uno, pero una sola restricción única que contiene ambos, por ejemplo, no se permiten 2 filas con el mismo padre y la misma LocalIdentifier) ​​

alter table bar add constraint unique_bar unique (parent_id, local_identifier) 

Y el código que los utiliza:

//foo is persistent, foo id = 1 
Bars bars = foo.getBars(); 
bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"] 
Bar newBar = new Bar(); 
newBar.setParent(foo); 
newBar.setLocalIdentifier("a"); 
bars.add(newBar); 

Ahora, por alguna razón, Hibernate no ejecuta las cosas en el orden en que fueron llamados. No ejecuta el clear() (borrar) antes de la add() (relleno), pero al revés, primero intenta insertar, para conseguir una ConstraintViolationException

Sé que la adición de un poco de session.flush() después bars.clear();, podría solucionar este problema, pero en este caso , No tengo acceso a la sesión de una manera no fea.

Entonces, ¿el color es la única solución? o hay una versión de Hibernate que respeta el orden de las acciones?

Actualización: Por cierto, eliminación de referencias a la colección dará lugar a un HibernateException de https://www.hibernate.org/117.html#A3:

consigo HibernateException: No eliminar la referencia de una colección con cascada = "all-eliminar -orphan " Esto sucederá si carga un objeto con una cascada =" all-delete-huérfano " colección y luego elimina la referencia a la colección. No reemplace esta colección, use clear() para que el algoritmo de eliminación huérfana pueda detectar su cambio.

+2

Creo que el enrojecimiento es la única opción aquí – ruchirhhi

+0

Relativa [tema del foro de Hibernate] (https://forum.hibernate.org/viewtopic.php?t=934483). –

Respuesta

8

supongo que no hay alternativa al lavado

De here:

Hibernate está violando una restricción única!

Hibernate no es tan inteligente con restricciones únicas ya que es con claves externas. A veces, es posible que necesite dar una pequeña pista.

Una violación restricción única podría ocurrir si dos objetos son a la vez de ser actualizado , uno está "liberando" un valor y el otro es "la obtención de" el mismo valor . Una solución alternativa es flush() la sesión manualmente después de actualizar el primer objeto y antes de actualizar el segundo.

(Este tipo de problema se produce raramente en la práctica .)

1

Si se quiere evitar el lavado de la sesión aquí, tratar de reemplazar toda la lista (en lugar de new List<Bar>()Clear()). Hibernate en realidad debería eliminar todos los elementos en una sola toma antes de agregar nueva. Solo un intento, no estoy seguro de si funciona.

+1

Gracias, pero no: https://www.hibernate.org/117.html#A3 Actualizaré la pregunta –

1

Si está utilizando Oracle, también se puede utilizar restricciones diferibles posponer la comprobación de las restricciones hasta que se confirme la transacción. No estoy seguro de si/cómo esto es compatible con otras bases de datos.

Cuestiones relacionadas