2009-05-05 44 views
10

我有以下方式储蓄双向多对多

@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”,吸气的实例将返回B的正确子集。但是,如果我更改了'A'中的Bs列表,那么这些更改不会存储在数据库中?

我的问题是,我该如何做到这一点,以便两个班级的变化都可以“级联”到另一个班级?

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

+0

哪些JPA实现您使用? – 2009-05-22 00:15:13

回答

16

最短的答案似乎是你不能,它是有道理的。在双向多对多关联中,一方必须是主人,并且用于持久更改底层连接表。由于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?那么a2不应该知道b?

这就是为什么您必须自己维护双向关联(并且使上述示例无法到达,即使在内存中),JPA也只会基于其一侧的状态持续存在。

0

你有没有tryed您所指定的反向连接列添加的mappedBy参数到某个字段B类像这样

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

这不起作用,它实际上是一个非法参数化。 mappedBy参数定义了字段的所有权,因此两个集合都不能使用该参数,因为它们不能彼此拥有。 – 2009-05-05 12:43:30

3

@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。

+0

我曾试过这个解决方案,但没有运气:( – 2009-05-06 05:38:17

0

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

 
    @Entity 
    class B { 
    @ManyToMany 
    @JoinTable (
     name="A_B", 
     joinColumns = {@JoinColumn(name="B_ID")}, 
     inverseJoinColumns = {@JoinColumn(name="A_ID")} 
    ) 
    private List a; 
    .. 
} 
1

由于工作的关系是双向的,从而将应用程序更新的关系 一面,另一面也应得到更新, 并同步。在JPA中,如在Java中一般这是应用程序的 责任,或者维持 关系的对象模型。如果您的应用程序添加到 关系的一侧,则它必须添加到另一侧。

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

来源:OneToMany#Getters_and_Setters