【问题标题】:@ManyToMany JPA relation using a 2nd degree relationship in join table and UK@ManyToMany JPA 关系在连接表和英国中使用二级关系
【发布时间】:2015-10-18 21:51:37
【问题描述】:

我有这个实体模型(简化):

@Entity
class A {
  @Id
  String id;

  Collection<B> bs;
}

@Entity
class B {
  @Id
  String id;

  @ManyToOne
  @JoinColumn(name = "c_id", nullable = false)
  C c;
}

@Entity
class C {
  @Id
  String id;
}

在 A 和 B 之间添加连接表(多对多关系)并使用 A.id 和 B.c.id 强制执行复合 UK 的最佳方法是什么?

我尝试过这样的事情:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable
        (name = "a_b",
                joinColumns = @JoinColumn(name = "a_id"),
                inverseJoinColumns = {
                        @JoinColumn(name = "b_id", referencedColumnName = "id"),
                        @JoinColumn(name = "c_id", referencedColumnName = "c_id")},
                uniqueConstraints = @UniqueConstraint(name = "uk_a_c", columnNames = {"a_id", "c_id"}))

但我得到一个MultipleBagFetchException,这很奇怪。这一定与c_id不是主键的一部分有关。如果我从inverseJoinColumns 中删除c_id,它会按预期工作,但这不是我需要的。

【问题讨论】:

    标签: java hibernate jpa many-to-many hibernate-mapping


    【解决方案1】:

    我的最终映射如下所示:

    @Entity
    @EntityListeners(ABListener.class)
    @Table(name = "a_b", uniqueConstraints =
    @UniqueConstraint(name = "uk_rel_a_b", columnNames = {"a_id", "c_id"}))
    public class AB extends BaseEntity<Long> {
    
        private Long id;
    
        @ManyToOne(optional = false)
        @JoinColumn(name = "a_id")
        private A a;
    
        @ManyToOne(optional = false)
        @JoinColumn(name = "b_id")
        private B b;
    
        @ManyToOne(optional = false)
        @JoinColumn(name = "c_id")
        private C c;
    
        public AB(A a, B b) {
            this.a = a;
            this.b = b;
        }
        /* rest of the class */
    }
    

    还有一个监听器来处理C的设置:

    public class ABListener {
    
        @PrePersist
        @PreUpdate
        void handleCUpdate(AB ab) {
            if (ab.getB() != null) {
                ab.setC(ab.getB().getC());
            }
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      如果 B 和 C 之间是一对一的关联,你可以在这两者之间共享主键,这样

      B.id = C.id = B.c.id
      

      那么连接表唯一键可以在A.id和B.id之间。

      【讨论】:

      • 那很快 :) 谢谢。对不起,但我的问题不完整。 B 和 C 之间是多对一。
      • 如果它是多对一而不是复制 B-C 关系,您可以使用预插入验证触发器在数据库中执行此操作。无论如何,B 已经与 A(因为从 A 到 B 存在一对多关联)和与 C(因为从 B 到 C 存在多对一关联)相关联。所以 B 已经是 A 和 C 的链接表,因此可以在 B 中将 UK 添加为 (a.id, c.id)
      • A-B 是多对多关系。我正在考虑使用带有 b.id 和 b.c_id 作为 inverseJoinColumns 的 JoinTable,但是由于 c_id 不是 pk 的一部分,它似乎不起作用(我得到了 MultipleBagFetchException)
      • MultipleBagFetchException 如果我们必须要 EAGER 列表或者您尝试 JOIN FETCH 两个列表,则会被抛出。尽管您最终得到的是笛卡尔积,但它适用于集合。
      • 我知道这通常是问题所在,但所有 *ToMany 关系都是惰性的。如果我只在 inverseJoinColumns 中留下 pk,我不会再收到错误,所以我认为它与 inverseJoinColumns 中有一个非 pk 列有关。但我没有找到任何关于此的文档。
      猜你喜欢
      • 2021-07-31
      • 2014-11-15
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      • 2016-09-08
      • 2011-09-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多