从如上所述映射的列表中删除元素时遇到问题。这是映射:
@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; } }
插入Bar-instances并保存Foo工作正常,但是当我从列表中删除元素并再次保存时,违反了映射表中bar_id的唯一约束。以下SQL语句由hibernate发布,看起来很奇怪:
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"
错误完全有意义,鉴于Hibernate生成的语句(列表中有五个项目,我删除第一个,Hibernate删除带有LAST索引的映射行,并尝试更新剩余的那些,从第一个)。
上面的映射有什么问题?
答案 0 :(得分:15)
您的映射完全有效,并且作为JPA 2.0实现与EclipseLink一起使用(当然没有Fetch
注释),但实际上Hibernate失败了。
这是带有Hibernate的DDL:
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
我们假设Foo#1
包含Bar#1
,Bar#2
,Bar#3
的列表,连接表包含:
foo_id | bar_id | order_index
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
当删除时,比如列表中的第一项,从连接表中首先delete
最后一行(WTF?)Hibernate:
foo_id | bar_id | order_index
1 | 1 | 1
1 | 2 | 2
然后尝试update
联接表中的bar_id
列而不是order_index
(WTF!?),以反映列表中项目的“新”排序。首先(示意图):
foo_id | bar_id | order_index
1 | 2 | 1
1 | 2 | 2
下一步将导致:
foo_id | bar_id | order_index
1 | 2 | 1
1 | 3 | 2
显然,由于unique
上的bar_id
约束,这种方法听起来不对,不起作用。更一般地说,为什么Hibernate会混淆bar_id
而不是更新order_index
列?
答案 1 :(得分:0)
通常在通过连接表加入时,关系是ManyToMany而不是OneToMany。试试这个
@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;
}
答案 2 :(得分:0)
我猜你需要的是正确的逆映射 http://docs.jboss.org/hibernate/core/3.3/reference/en/html/tutorial.html#tutorial-associations-bidirectional
答案 3 :(得分:0)
不,我不认为这是一个hibernate错误,因为你会看到你是否进行搜索,这个由Pascal Thivent引用的hibernate bug是自2006年以来已知的一个bug,从未解决过。
为什么?
因为我认为问题只是在表上的约束而不是在休眠状态。
我不明白为什么bar_id
存在唯一约束使用订单索引意味着您的集合是List(而不是Set!)。 List是一个集合,您可以在其中指定要添加的元素的索引(它对应于OrderColumn) List和Set之间的区别在于您可以使用相同的数据两次(或更多),但相同的数据将位于不同的索引中。 然后,您可以使用相同的bar_id指定不同的索引,而不必在bar_id上指定唯一约束。 并且主键不能(foo_id,order_index)导致模式List在不同索引处授权相同的数据。 也许你的PK应该是(foo_id,bar_id,order_index)?
我认为问题就是这样:)