簡體   English   中英

在刪除元素時,Hibernate單向OneToMany映射中的約束違反,包括JoinTable和OrderColumn

[英]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#1Bar#2Bar#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_idunique約束,這種方法聽起來不正確並且不起作用 更一般地說,為什么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;
}

不,我不認為這是一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM