代码之家  ›  专栏  ›  技术社区  ›  tbk

移除元素时Hibernate单向OneToMany映射中的JoinTable和OrderColumn约束冲突

  •  16
  • tbk  · 技术社区  · 15 年前

    从如上所述映射的列表中删除元素时出现问题。这是地图:

    @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;
        }
    }
    

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

    4 回复  |  直到 15 年前
        1
  •  15
  •   beat Chinnery    10 年前

    您的映射是完全有效的,并与EclipseLink作为JPA2.0实现一起工作(没有 Fetch 当然是注释),但Hibernate确实失败了。

    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
    

    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
    

    显然,这种方法听起来不对 不起作用 因为 unique 约束 酒吧id . 更普遍地说,为什么冬眠会搅乱 而不是更新 专栏?

    我认为这是一个冬眠虫(报告如下 HHH-5694 HHH-1268 现在)。

        2
  •  0
  •   mR_fr0g    15 年前

    通常通过联接表联接时,关系是多对多,而不是一对多。试试这个

    @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;
    }
    
        4
  •  0
  •   Nico    15 年前

    不,我不认为这是一个hibernate bug,如果你搜索这个hibernate bug,你会发现这个被Pascal Thivent引用的bug是一个自2006年以来就知道的bug,而且从未被解决过。

    因为我认为问题只在表的约束中,而不是在hibernate中。

    我不明白为什么酒吧标识有唯一的限制

    使用顺序索引意味着您的集合是一个列表(而不是一个集合!)。 列表是一个集合,您可以在其中为添加的元素指定索引(它对应于OrderColumn)。
    然后,您可以将同一个bar_id设置为不同的索引,而不必对bar_id指定唯一约束。 主键不能是(foo_id,order_index),因为模式列表在不同的索引上授权相同的数据。 也许你的主键应该是(foo_id,bar_id,order_index)?

    我认为问题是这样的:)