简体   繁体   English

在删除元素时,Hibernate单向OneToMany映射中的约束违反,包括JoinTable和OrderColumn

[英]Constraint violation in Hibernate unidirectional OneToMany mapping with JoinTable and OrderColumn when removing elements

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. 插入Bar-instances并保存Foo工作正常,但是当我从列表中删除元素并再次保存时,违反了映射表中bar_id的唯一约束。 The following SQL-statements are issued by hibernate, and these look quite odd: 以下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"

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? 上面的映射有什么问题?

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. 您的映射完全有效,并且与EclipseLink一起使用作为JPA 2.0实现(当然没有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#1Bar#2Bar#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: 当删除时,比如列表中的第一项,Hibernate首先从连接表中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. 然后尝试update连接表中的bar_id列而不是order_index (WTF!?)以反映列表中项目的“新”排序。 First (schematically): 首先(示意图):

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 work because of the unique constraint on bar_id . 显然,由于bar_idunique约束,这种方法听起来不正确并且不起作用 More generally, why the hell does Hibernate mess with the bar_id instead of updating the order_index column? 更一般地说,为什么Hibernate会使用bar_id而不是更新order_index列?

I consider this to be an Hibernate bug (reported as HHH-5694 , see HHH-1268 now). 我认为这是一个Hibernate错误(报告为HHH-5694 ,现在请参阅HHH-1268 )。

Usually when joining through a join table the relationship is ManyToMany not OneToMany. 通常在通过连接表加入时,关系是ManyToMany而不是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;
}

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. 不,我不认为这是一个hibernate错误,并且你会看到你是否进行搜索,这个由Pascal Thivent引用的hibernate bug是一个自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 !). 使用订单索引意味着您的集合是List(而不是Set!)。 And a List is a collection where you can specify index to elements you add (it corresponds to OrderColumn). List是一个集合,您可以在其中指定要添加的元素的索引(它对应于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. List和Set之间的区别在于您可以使用相同的数据两次(或更多),但相同的数据将位于不同的索引中。 Then you can have the same bar_id a different indexes, you don't have to specify a unique constraint on bar_id. 然后,您可以使用相同的bar_id指定不同的索引,而不必在bar_id上指定唯一约束。 And the primary key can't be (foo_id, order_index) cause the pattern List authorize the same data at different indexes. 并且主键不能(foo_id,order_index)导致模式List在不同索引处授权相同的数据。 Maybe your PK should be (foo_id, bar_id, order_index) ? 也许你的PK应该是(foo_id,bar_id,order_index)?

I think the problem is in this way :) 我认为问题就是这样:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM