spring JPA @OneToMany -> 父 - 子参考(外键)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9533676/
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
JPA @OneToMany -> Parent - Child Reference (Foreign Key)
提问by Sim0rn
i have a Question about referencing ParentEntities from Child Entites ir If i have something like this:
我有一个关于从 Child Entites 引用 ParentEntities 的问题,如果我有这样的事情:
Parent.java:
父.java:
@Entity(name ="Parent")
public class Parent {
@Id
@Generate.....
@Column
private int id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent")
private Set<Child> children;
simple ... getter and setter ...
}
And the Child.java:
和 Child.java:
@Entity(name ="Child")
public class Child{
@Id
@Generate....
@Column
private int id;
@ManyToOne
private Parent parent;
... simple getter an setter
}
Following Tables are going to be created:
将创建以下表:
Parent:
int id
Child:
int id
int parent_id (foreign key: parent.id)
Ok, so far, everthings fine. But when it comes to using this Reference from Java, i would think, you can do something like this.
好的,到目前为止,一切都很好。但是当谈到从 Java 使用这个 Reference 时,我想,你可以做这样的事情。
@Transactional
public void test() {
Parent parent = new Parent();
Child child = new Child();
Set<Child> children = new HashSet<Child>();
children.add(child);
parent.setChildren(children);
entityManager.persist(parent);
}
which leads to this in Database:
这导致了数据库中的这一点:
Parent:
id
100
Child
id paren_id
101 100
But thats not the case, you have to explicity set the Parent to the Child (which, i would think, the framework could probably do by itself).
但事实并非如此,您必须明确地将父级设置为子级(我认为,框架可能可以自行完成)。
So whats really in the database is this:
那么数据库中真正的内容是这样的:
Parent:
id
100
Child
id paren_id
101 (null)
cause i haven't set the Parent to the Child. So my Question:
因为我还没有将父级设置为子级。所以我的问题:
Do I really have to do sth. like this?
我真的必须做某事吗?像这样?
Parent.java:
父.java:
...
setChildren(Set<Child> children) {
for (Child child : children) {
child.setParent.(this);
}
this.children = children;
}
...
Edit:
编辑:
According to the fast Replies i was able to solve this Problem by using the @JoinColumn on the Reference-Owning Entity. If we take the Example from above, i did sth. like this:
根据快速回复,我能够通过在引用拥有实体上使用 @JoinColumn 来解决这个问题。如果我们从上面的例子中,我做了某事。像这样:
Parent.java:
父.java:
@Entity(name ="Parent")
public class Parent {
@Id
@Generate.....
@Column
private int id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name= "paren_id")
private Set<Child> children;
simple ... getter and setter ...
}
And the Child.java:
和 Child.java:
@Entity(name ="Child")
public class Child{
@Id
@Generate....
@Column
private int id;
... simple getter an setter
}
Now if we do this:
现在,如果我们这样做:
@Transactional
public void test() {
Parent parent = new Parent();
Child child = new Child();
Set<Child> children = new HashSet<Child>();
children.add(child);
parent.setChildren(children);
entityManager.persist(parent);
}
The Reference is correctly set by the Parent:
父级正确设置了参考:
Parent:
id
100
Child
id paren_id
101 100
Thanks for the Answers.
感谢您的回答。
采纳答案by beerbajay
Do I really have to do sth. like this?
我真的必须做某事吗?像这样?
That is one strategy, yes.
这是一种策略,是的。
On bi-directional relationships there is an "owning" and a "non-owning" side of the relationship. Because the owning side in your case is on Child, you need to set the relationship there for it to be persisted. The owning side is usually determined by where you specify @JoinColumn, but it doesn't look like you're using that annotation, so it's likely being inferred from the fact that you used mappedByin the Parentannotation.
在双向关系中,关系有“拥有”和“非拥有”的一面。因为您的案例中的拥有方是 on Child,所以您需要在那里设置关系以使其持久化。拥有方通常由您指定的位置决定@JoinColumn,但看起来您并未使用该批注,因此很可能是从您mappedBy在Parent批注中使用的事实推断出来的。
You can read a lot more about this here.
您可以在此处阅读更多相关信息。
回答by pirho
It still seems to be the case. In parent Entityyou can have something like
情况似乎仍然如此。在父母中,Entity您可以拥有类似的东西
@PrePersist
private void prePersist() {
children.forEach( c -> c.setParent(this));
}
in order to avoid repeating code for setting child/parent relationship elsewhere in code.
以避免在代码中的其他地方重复设置子/父关系的代码。
回答by Phil Brock
We ran into a problem while persisting a simple object graph like the one shown above. Running in H2 everything would work, but when we ran against MySQL the "paren_id" in the child table (defined in the @JoinColumn annotation) wasn't getting populated with the generated id of the parent - even though it was set as a non-null column with a foreign key constraint in the DB.
我们在持久化一个简单的对象图时遇到了一个问题,如上图所示。在 H2 中运行一切正常,但是当我们针对 MySQL 运行时,子表中的“paren_id”(在 @JoinColumn 注释中定义)没有填充父表的生成 id - 即使它被设置为非-null 列在数据库中具有外键约束。
We'd get an exception like this:
我们会得到这样的异常:
org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value
For anyone else who might run into this, what we eventually found was that we had to another attribute to the @JoinColumnto get it to work:
对于可能遇到此问题的任何其他人,我们最终发现我们必须使用另一个属性@JoinColumn才能使其工作:
@JoinColumn(name="paren_id", nullable=false)
回答by Mikko Maunu
Yes, that is the case. JPA does not keep care about consistency of your entity graph. Especially you have to set it to the owner side of bidirectional relationship (in your case to the parent attribute of Child).
是的,就是这样。JPA 不关心实体图的一致性。特别是您必须将其设置为双向关系的所有者端(在您的情况下为 Child 的父属性)。
In JPA 2.0 specification this is said with following words:
在 JPA 2.0 规范中,这是用以下词语表示的:
Note that it is the application that bears responsibility for maintaining the consistency of run- time relationships—for example, for insuring that the “one” and the “many” sides of a bidi- rectional relationship are consistent with one another when the application updates the relationship at runtime.
请注意,应用程序负责维护运行时关系的一致性——例如,确保在应用程序更新时双向关系的“一”边和“多”边彼此一致运行时的关系。
回答by Jo?o Rodrigues
If I am getting you correctly, according to EntityManager, if you want it to manage the transaction's insert order your have to "tell him" that it should persist the children too. And you are not doing that, so "he" doesn't know what to persist, but your parent's child list is not empty so "he" takes it has correct but the stored value is null.
如果我正确地告诉您,根据EntityManager,如果您希望它管理事务的插入顺序,您必须“告诉他”它也应该坚持孩子。而你没有这样做,所以“他”不知道要坚持什么,但是你父母的孩子列表不是空的,所以“他”认为它是正确的,但存储的值为空。
So you should consider do something like:
所以你应该考虑做这样的事情:
... begin, etc
em.persist(child)
em.persist(parent)
do what you want with the parent object here then commit and this should work for similar cases too.
在这里对父对象做你想做的事情然后提交,这也适用于类似的情况。

