删除元素时,使用 JoinTable 和 OrderColumn 的休眠单向 OneToy 映射中的约束冲突

2022-09-02 13:38:59

从如上所述映射的列表中删除元素时,我遇到了问题。下面是映射:

@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实例并保存Foo工作正常,但是当我从列表中删除元素并再次保存时,违反了映射表中bar_id的唯一约束。以下 SQL 语句由休眠发出,这些语句看起来很奇怪:

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索引的映射行,并尝试更新其余的,从第一个开始)。

上面的映射有什么问题?


答案 1

你的映射是完全有效的,并且可以与EclipseLink一起使用作为JPA 2.0实现(当然没有注释),但使用Hibernate确实失败了。Fetch

以下是带有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#1Bar#1Bar#2Bar#3

foo_id | bar_id | order_index
     1 |      1 |           1
     1 |      2 |           2
     1 |      3 |           3

删除时,请说出列表中的第一项,先休眠连接表中的最后一行 (WTF?):delete

foo_id | bar_id | order_index
     1 |      1 |           1
     1 |      2 |           2

然后尝试连接表中的列而不是(WTF!?)以反映列表中项目的“新”顺序。第一(示意性):updatebar_idorder_index

foo_id | bar_id | order_index
     1 |      2 |           1
     1 |      2 |           2

其中,下一步将导致:

foo_id | bar_id | order_index
     1 |      2 |           1
     1 |      3 |           2

显然,这种方法听起来不对,并且由于 对 的约束而不起作用。更一般地说,为什么Hibernate会弄乱而不是更新列?uniquebar_idbar_idorder_index

我认为这是一个休眠错误(报告为HHH-5694,现在请参阅HHH-1268)。


答案 2

通常,当通过联接表联接时,关系是 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;
}

推荐