删除元素时,Hibernate单向OneToMany映射中的约束违反,包括JoinTable和OrderColumn
从上面描述的映射中删除元素时遇到问题。 这是映射:
@实体 @Table(name =“foo”) class Foo { 私人名单栏; @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(){ 返回栏; } }
插入Bar-instances并保存Foo工作正常,但是当我从列表中删除元素并再次保存时,违反了映射表中bar_id的唯一约束。 以下SQL语句是由hibernate发布的,这看起来很奇怪:
日志:执行:从foo_bar_map删除,其中foo_id = $ 1,order_index = $ 2 细节:参数:$ 1 ='4',$ 2 ='6' 日志:执行S_5:更新foo_bar_map set bar_id = $ 1其中foo_id = $ 2和order_index = $ 3 细节:参数:$ 1 = '88',$ 2 ='4',$ 3 ='0' 错误:重复键值违反唯一约束“foo_bar_map_bar_id_key”
这个错误完全有意义,考虑到Hibernate生成的语句(列表中有五个项目,我删除第一个项目,Hibernate删除带有LAST索引的映射行,并尝试更新剩余的项目,从第一个开始) 。
上面的映射有什么问题?
您的映射完全有效,并且与EclipseLink一起用作JPA 2.0实现(当然没有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
当删除时,比如列表中的第一项,Hibernate首先从连接表中delete
最后一行(WTF?):
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
显然,由于bar_id
的unique
约束,这种方法听起来不对, 不起作用 。 更一般地说,为什么Hibernate会使用bar_id
而不是更新order_index
列?
我认为这是一个Hibernate错误(报告为HHH-5694 ,现在请参阅HHH-1268 )。
通常在通过连接表加入时,关系是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; }
我想你需要的是正确的逆映射。
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/tutorial.html#tutorial-associations-bidirectional
不,我不认为这是一个hibernate错误,因为你会看到你是否进行搜索,这个由Pascal Thivent引用的hibernate bug是一个自2006年以来就已知的错误,从未解决过。
为什么?
因为我认为问题只是在表的约束而不是hibernate。
我不明白为什么bar_id有一个独特的约束
使用订单索引意味着您的集合是List(而不是Set!)。 List是一个集合,您可以在其中指定要添加的元素的索引(它对应于OrderColumn)。
List和Set之间的区别在于您可以使用相同的数据两次(或更多),但相同的数据将位于不同的索引中。 然后,您可以使用相同的bar_id作为不同的索引,而不必在bar_id上指定唯一约束。 并且主键不能(foo_id,order_index)导致模式List在不同索引处授权相同的数据。 也许你的PK应该是(foo_id,bar_id,order_index)?
我认为问题就是这样:)