![](/img/trans.png)
[英]Hibernate - OneToMany UniDirectional Mapping - SQLGrammarException
[英]Constraint violation in Hibernate unidirectional OneToMany mapping with JoinTable and OrderColumn when removing elements
從上面描述的映射中刪除元素時遇到問題。 這是映射:
@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索引的映射行,並嘗試更新剩余的那些,從第一個開始) 。
上面的映射有什么問題?
您的映射完全有效,並且與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
列?
通常在通過連接表加入時,關系是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;
}
不,我不認為這是一個hibernate錯誤,並且你會看到你是否進行搜索,這個由Pascal Thivent引用的hibernate bug是一個自2006年以來已知的錯誤,並且從未解決過。
為什么?
因為我認為問題只是在表上的約束而不是休眠。
我不明白為什么bar_id有一個獨特的約束
使用訂單索引意味着您的集合是List(而不是Set!)。 List是一個集合,您可以在其中指定要添加的元素的索引(它對應於OrderColumn)。
List和Set之間的區別在於您可以使用相同的數據兩次(或更多),但相同的數據將位於不同的索引中。 然后,您可以使用相同的bar_id指定不同的索引,而不必在bar_id上指定唯一約束。 並且主鍵不能(foo_id,order_index)導致模式List在不同索引處授權相同的數據。 也許你的PK應該是(foo_id,bar_id,order_index)?
我認為問題就是這樣:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.