java 保存双向多对多
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/824600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Saving bidirectional ManyToMany
提问by Kim L
I have two entity classes annotated in the following way
我用以下方式注释了两个实体类
@Entity
class A {
@ManyToMany(mappedBy="A", cascade=CascadeType.ALL)
private List<B> b;
..
}
@Entity
class B {
@ManyToMany(cascade=CascadeType.ALL)
private List<A> a;
..
}
If I store an instance of the class 'B', the relations are stored in the database and the getter in class 'A' will return the correct subset of B's. However, if I make changes to the list of Bs in 'A', the changes are not stored in the database?
如果我存储类“B”的实例,则关系存储在数据库中,“A”类中的 getter 将返回 B 的正确子集。但是,如果我对“A”中的 B 列表进行更改,更改不会存储在数据库中?
My question is, how can I make it so that changes in either class are "cascaded" to the other class?
我的问题是,如何才能使任一类中的更改“级联”到另一个类?
EDIT: I've tried different variations of removing the mappedBy-parameter and defining a JoinTable (and columns), but I've been unable to find the correct combination.
编辑:我尝试了删除mappedBy参数和定义JoinTable(和列)的不同变体,但我一直无法找到正确的组合。
回答by Louis Jacomet
The shortest answer seems to be you cannot and it makes sense. In a bidirectional many-to-many association one side must be master and is used to persist changes to the underlying join table. As JPA will not maintain both side of the association, you could end up with a memory situation that could not be reloaded once stored in the database. Example:
最短的答案似乎是你不能,这是有道理的。在双向多对多关联中,一侧必须是主控方,用于将更改持久化到底层连接表。由于 JPA 不会维护关联的双方,因此您最终可能会遇到一旦存储在数据库中就无法重新加载的内存情况。例子:
A a1 = new A();
A a2 = new A();
B b = new B();
a1.getB().add(b);
b.getA().add(a2);
If this state could be persisted, you would end up with the following entries in the join table:
如果这种状态可以持久化,您将在连接表中得到以下条目:
a1_id, b_id
a2_id, b_id
But upon loading, how would JPA know that you intended to only let b know about a2 and not a1 ? and what about a2 that should not know about b ?
但是在加载时,JPA 怎么会知道您打算只让 b 知道 a2 而不是 a1 ?那么不应该知道 b 的 a2 呢?
This is why you have to maintain the bidirectional association yourself (and make the above example impossible to get to, even in memory) and JPA will only persist based on the state of one side of it.
这就是为什么您必须自己维护双向关联(并使上面的示例无法访问,即使在内存中)并且 JPA 只会根据其一侧的状态持续存在。
回答by A_M
Have you specified the inverse join columns?
您是否指定了反向连接列?
@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;
..
}
That's assuming a join table called A_B with columns A_ID and B_ID.
假设有一个名为 A_B 的连接表,其中包含 A_ID 和 B_ID 列。
回答by Tomasz
As the relationship is bi-directional so as the application updates one side of the relationship, the other side should also get updated, and be in synch. In JPA, as in Java in general it is the responsibility of the application, or the object model to maintain relationships.If your application adds to one side of a relationship, then it must add to the other side.
This can be resolved through add or set methods in the object model that handle both sides of the relationships, so the application code does not need to worry about it. There are two ways to go about this, you can either only add the relationship maintenance code to one side of the relationship, and only use the setter from one side (such as making the other side protected), or add it to both sides and ensure you avoid a infinite loop.
由于关系是双向的,因此应用程序更新关系的一侧时,另一侧也应该得到更新,并且保持同步。在 JPA 中,就像在 Java 中一样,通常由应用程序或对象模型负责维护关系。如果您的应用程序添加到关系的一侧,那么它必须添加到另一侧。
这可以通过处理双方关系的对象模型中的 add 或 set 方法来解决,因此应用程序代码无需担心。有两种方法可以解决这个问题,您可以只在关系的一侧添加关系维护代码,并且只使用一侧的setter(例如使另一侧受到保护),或者将其添加到双方并确保您避免无限循环。
Source: OneToMany#Getters_and_Setters
回答by mR_fr0g
Have you tryed adding the mappedBy parameter onto the A field in class B like so
您是否尝试过将 mappingBy 参数添加到 B 类中的 A 字段中
@Entity
class B {
@ManyToMany(cascade=CascadeType.ALL, mappedBy = "b")
private List<A> a;
..
}
回答by Jozeph
Maybe there is a small mistake in A_M's answer. In my opinion it should be:
可能 A_M 的回答有一个小错误。在我看来应该是:
@Entity
class B {
@ManyToMany
@JoinTable (
name="A_B",
joinColumns = {@JoinColumn(name="B_ID")},
inverseJoinColumns = {@JoinColumn(name="A_ID")}
)
private List a;
..
}

