繁体   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