java 删除元素时使用 JoinTable 和 OrderColumn 的 Hibernate 单向 OneToMany 映射中的约束冲突
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4022509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Constraint violation in Hibernate unidirectional OneToMany mapping with JoinTable and OrderColumn when removing elements
提问by tbk
I have a problem when removing elements from a list mapped as described above. Here is the mapping:
从如上所述映射的列表中删除元素时遇到问题。这是映射:
@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; } }
Inserting Bar-instances and saving the Foo works fine, but when I remove an element from the list and save again, the unique constraint on bar_id in the mapping table is violated. The following SQL-statements are issued by hibernate, and these look quite odd:
插入 Bar-instances 并保存 Foo 工作正常,但是当我从列表中删除一个元素并再次保存时,映射表中 bar_id 的唯一约束被违反。以下 SQL 语句由 hibernate 发出,它们看起来很奇怪:
LOG: execute : delete from foo_bar_map where foo_id= and order_index= DETAIL: parameters: = '4', = '6' LOG: execute S_5: update foo_bar_map set bar_id= where foo_id= and order_index= DETAIL: parameters: = '88', = '4', = '0' ERROR: duplicate key value violates unique constraint "foo_bar_map_bar_id_key"
The error perfectly makes sense, given the statements generated by Hibernate (there are five items in the list, I remove the first one and Hibernate deletes the mapping row with the LAST index and the tries to updates the remaining ones, starting with the first).
考虑到 Hibernate 生成的语句(列表中有五个项目,我删除了第一个项目,Hibernate 删除了带有 LAST 索引的映射行,并尝试更新其余的行,从第一个开始),该错误是完全有道理的.
What is wrong with the mapping above?
上面的映射有什么问题?
采纳答案by Pascal Thivent
Your mapping is totally valid and works with EclipseLink as JPA 2.0 implementation (without the Fetch
annotation of course), but indeed fails with Hibernate.
您的映射是完全有效的,并且可以作为 JPA 2.0 实现与 EclipseLink 一起使用(Fetch
当然没有注释),但在 Hibernate 中确实失败了。
Here is the DDL with 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
So let's say Foo#1
holds a list with Bar#1
, Bar#2
, Bar#3
, the join table contains:
因此,假设Foo#1
持有一个包含Bar#1
, Bar#2
,的列表Bar#3
,连接表包含:
foo_id | bar_id | order_index
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
When removing, say the first item from the list, Hibernate first delete
the last row (WTF?) from the join table:
删除时,说列表中的第一项,首先休眠delete
连接表中的最后一行(WTF?):
foo_id | bar_id | order_index
1 | 1 | 1
1 | 2 | 2
And then tries to update
the bar_id
column in the join table instead of the order_index
(WTF!?) to reflect the "new" ordering of the items in the list. First (schematically):
然后尝试连接表中update
的bar_id
列而不是order_index
(WTF!?)来反映列表中项目的“新”排序。首先(示意图):
foo_id | bar_id | order_index
1 | 2 | 1
1 | 2 | 2
where the next step would result in:
下一步将导致:
foo_id | bar_id | order_index
1 | 2 | 1
1 | 3 | 2
Obviously, this approach doesn't sound right and doesn't workbecause of the unique
constraint on bar_id
. More generally, why the hell does Hibernate mess with the bar_id
instead of updating the order_index
column?
显然,这种方法不健全的权利,并不起作用,因为的unique
上约束bar_id
。更一般地说,为什么 Hibernate 会弄乱bar_id
而不是更新order_index
列?
I consider this to be an Hibernate bug (reported as HHH-5694, see HHH-1268now).
回答by Nico
No I don't think it's a hibernate bug, and as you will see if you do searches this hibernate bug quoted by Pascal Thivent is a bug known since 2006 and has never been solved.
不,我不认为这是一个休眠错误,如果您进行搜索,您会看到 Pascal Thivent 引用的这个休眠错误是自 2006 年以来已知的错误,并且从未得到解决。
Why ?
为什么 ?
Cause I think the problem is just in the constraints on the table and not in hibernate.
因为我认为问题只是在桌子上的约束而不是在休眠中。
I don't understand why there is a unique constraint on bar_id
我不明白为什么对 bar_id 有唯一约束
Using an order index means your collection is a List (and not a Set !).
And a List is a collection where you can specify index to elements you add (it corresponds to OrderColumn).
The difference between a List and a Set is that you and can the same data twice (or more), but the same data will be at different indexes.
Then you can have the same bar_id a different indexes, you don't have to specify a unique constraint on bar_id.
And the primary key can't be (foo_id, order_index) cause the pattern List authorize the same data at different indexes.
Maybe your PK should be (foo_id, bar_id, order_index) ?
使用订单索引意味着您的集合是一个列表(而不是一个集合!)。List 是一个集合,您可以在其中指定添加的元素的索引(它对应于 OrderColumn)。
List 和 Set 之间的区别在于,您可以两次(或多次)访问相同的数据,但相同的数据将位于不同的索引处。然后你可以有相同的 bar_id 不同的索引,你不必在 bar_id 上指定唯一约束。并且主键不能是 (foo_id, order_index) 导致模式 List 在不同的索引处授权相同的数据。也许你的 PK 应该是 (foo_id, bar_id, order_index) ?
I think the problem is in this way :)
我认为问题是这样的:)
回答by mR_fr0g
Usually when joining through a join table the relationship is ManyToMany not OneToMany. Try this
通常当通过连接表连接时,关系是多对多而不是单对多。试试这个
@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;
}
回答by ch4nd4n
I guess what you need is correct inverse mapping.
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/tutorial.html#tutorial-associations-bidirectional
我猜你需要的是正确的逆映射。
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/tutorial.html#tutorial-associations-bidirectional