【问题标题】:Saving bidirectional ManyToMany保存双向多对多
【发布时间】:2018-03-12 03:07:42
【问题描述】:

我有两个实体类按以下方式注释

@Entity
class A {
   @ManyToMany(mappedBy="A", cascade=CascadeType.ALL)
   private List<B> b;
 ..
}

@Entity
class B {
   @ManyToMany(cascade=CascadeType.ALL)
   private List<A> a;
 ..
}

如果我存储“B”类的实例,则关系将存储在数据库中,“A”类中的 getter 将返回 B 的正确子集。但是,如果我对“A”中的 B 列表进行更改,更改不会存储在数据库中?

我的问题是,我怎样才能使任何一个类中的更改“级联”到另一个类?

编辑:我尝试了删除 mappedBy 参数和定义 JoinTable(和列)的不同变体,但我一直无法找到正确的组合。

【问题讨论】:

  • 您使用的是哪种 JPA 实现?

标签: java jpa


【解决方案1】:

最短的答案似乎是你不能,这是有道理的。在双向多对多关联中,一侧必须为主,用于将更改持久化到基础连接表。由于 JPA 不会维护关联的双方,因此您最终可能会遇到一旦存储在数据库中就无法重新加载的内存情况。 示例:

A a1 = new A();
A a2 = new A();
B b = new B();
a1.getB().add(b);
b.getA().add(a2);

如果这个状态可以被持久化,你最终会在连接表中得到以下条目:

a1_id, b_id
a2_id, b_id

但是在加载时,JPA 怎么知道您打算只让 b 知道 a2 而不是 a1 呢?那不应该知道b的a2呢?

这就是为什么您必须自己维护双向关联(并使上述示例无法访问,即使在内存中也是如此)并且 JPA 将仅根据其一侧的状态持续存在。

【讨论】:

    【解决方案2】:

    您是否指定了反向连接列?

    @Entity
    class A {
       @ManyToMany(mappedBy="A", cascade=CascadeType.ALL)
       private List <B> b;
       ..
    }
    
    @Entity 
    class B { 
       @ManyToMany 
       @JoinTable (
           name="A_B",
           joinColumns = {@JoinColumn(name="A_ID")},
           inverseJoinColumns = {@JoinColumn(name="B_ID")}
       )
       private List<A> a; 
       .. 
    } 
    

    假设有一个名为 A_B 的连接表,其中包含 A_ID 和 B_ID 列。

    【讨论】:

    • 不应该“mappedBy”等于“a”小写而不是类?
    【解决方案3】:

    由于关系是双向的,因此应用程序更新 关系的一方,另一方也应该得到更新, 并保持同步。在 JPA 中,就像在 Java 中一般 应用程序或维护对象模型的责任 关系。 如果您的应用程序添加到 关系,那么它必须添加到另一边。

    这可以通过对象模型中的add或set方法解决 处理关系的双方,所以应用程序代码 不需要担心。有两种方法可以解决这个问题, 您可以只将关系维护代码添加到一侧 的关系,并且只使用来自一侧的设置器(例如 使另一侧受到保护),或将其添加到两侧并确保 避免无限循环。

    来源:OneToMany#Getters_and_Setters

    【讨论】:

      【解决方案4】:

      您是否尝试过像这样将 mappedBy 参数添加到 B 类的 A 字段中

      @Entity
      class B {
         @ManyToMany(cascade=CascadeType.ALL, mappedBy = "b")
         private List<A> a;
       ..
      }
      

      【讨论】:

      • 这不行,它实际上是一个非法的参数化。 mappedBy 参数定义了字段的所有权,因此不可能对两个集合使用该参数,因为它们不能相互拥有。
      【解决方案5】:

      也许 A_M 的回答有一个小错误。 在我看来应该是:

      @实体 B类{ @ManyToMany @JoinTable ( 名称="A_B", joinColumns = {@JoinColumn(name="B_ID")}, inverseJoinColumns = {@JoinColumn(name="A_ID")} ) 私人名单a; .. }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-11
        • 1970-01-01
        相关资源
        最近更新 更多