java hibernate jpa jpa-2.0 one-to-many

java - Infracción de restricciones en Hibernate. El mapeo unidireccional de OneToMany con JoinTable y OrderColumn al eliminar elementos.



jpa jpa-2.0 (4)

Tengo un problema al eliminar elementos de una lista asignada como se describe anteriormente. Aquí está el mapeo:

@Entity @Table( name = "foo") class Foo { private List bars; @OneToMany @OrderColumn( name = "order_index" ) @JoinTable( name = "foo_bar_map", joinColumns = @JoinColumn( name = "foo_id" ), inverseJoinColumns = @JoinColumn( name = "bar_id" ) ) @Fetch( FetchMode.SUBSELECT ) public List getBars() { return bars; } }

Insertar instancias de barra y guardar el Foo funciona bien, pero cuando elimino un elemento de la lista y vuelvo a guardar, se viola la restricción única en bar_id en la tabla de mapeo. Las siguientes sentencias de SQL se emiten por hibernación, y estas parecen bastante extrañas:

LOG: execute : delete from foo_bar_map where foo_id=$1 and order_index=$2 DETAIL: parameters: $1 = ''4'', $2 = ''6'' LOG: execute S_5: update foo_bar_map set bar_id=$1 where foo_id=$2 and order_index=$3 DETAIL: parameters: $1 = ''88'', $2 = ''4'', $3 = ''0'' ERROR: duplicate key value violates unique constraint "foo_bar_map_bar_id_key"

El error tiene mucho sentido, dadas las declaraciones generadas por Hibernate (hay cinco elementos en la lista, elimino el primero y Hibernate elimina la fila de mapeo con el último índice y trata de actualizar los restantes, comenzando con el primero) .

¿Qué hay de malo con la asignación de arriba?


No, no creo que sea un error de hibernación, y como verá si busca este error de hibernación citado por Pascal Thivent es un error conocido desde 2006 y nunca se ha solucionado.

Por qué ?

Porque creo que el problema está en las restricciones de la tabla y no en hibernación.

No entiendo por qué hay una restricción única en bar_id

Usar un índice de orden significa que su colección es una Lista (y no un Conjunto). Y una Lista es una colección donde puede especificar el índice de los elementos que agregue (corresponde a OrderColumn).
La diferencia entre una Lista y un Conjunto es que usted y los mismos datos pueden dos veces (o más), pero los mismos datos estarán en índices diferentes. Entonces, puede tener el mismo bar_id en un índice diferente, no tiene que especificar una restricción única en bar_id. Y la clave principal no puede ser (foo_id, order_index) porque la Lista de patrones autoriza los mismos datos en diferentes índices. Tal vez tu PK debería ser (foo_id, bar_id, order_index)?

Creo que el problema es de esta manera :)


Por lo general, cuando se une a través de una tabla de unión, la relación es ManyToMany no OneToMany. Prueba esto

@ManyToMany @OrderColumn( name = "order_index" ) @JoinTable( name = "foo_bar_map", joinColumns = @JoinColumn( name = "foo_id" ), inverseJoinColumns = @JoinColumn( name = "bar_id" ) ) @Fetch( FetchMode.SUBSELECT ) public List getBars() { return bars; }



Su asignación es totalmente válida y funciona con EclipseLink como implementación JPA 2.0 (sin la anotación Fetch por supuesto), pero de hecho falla con Hibernate.

Aquí está el DDL con Hibernate:

create table foo_bar_map (foo_id bigint not null, bar_id bigint not null, order_index integer not null, primary key (foo_id, order_index), unique (bar_id)) alter table foo_bar_map add constraint FK14F1CB7FA042E82 foreign key (bar_id) references Bar4022509 alter table foo_bar_map add constraint FK14F1CB7B6DBCCDC foreign key (foo_id) references Foo4022509

Así que digamos que Foo#1 tiene una lista con la Bar#1 , Bar#2 , Bar#3 , la tabla de unión contiene:

foo_id | bar_id | order_index 1 | 1 | 1 1 | 2 | 2 1 | 3 | 3

Al eliminar, diga el primer elemento de la lista, Hibernate primero delete la última fila (WTF?) De la tabla de unión:

foo_id | bar_id | order_index 1 | 1 | 1 1 | 2 | 2

Y luego intenta update la columna bar_id en la tabla de unión en lugar de order_index (WTF !?) para reflejar el orden "nuevo" de los elementos en la lista. Primero (esquemáticamente):

foo_id | bar_id | order_index 1 | 2 | 1 1 | 2 | 2

donde el siguiente paso resultaría en:

foo_id | bar_id | order_index 1 | 2 | 1 1 | 3 | 2

Obviamente, este enfoque no suena bien y no funciona debido a la restricción unique en bar_id . Más generalmente, ¿por qué diablos Hibernate se bar_id con el bar_id lugar de actualizar la columna order_index ?

Considero que esto es un error de Hibernate (reportado como HHH-5694 , vea HHH-1268 ahora).