i have a Question about referencing ParentEntities from Child Entites ir If i have something like this:
我有一个关于从Child Entites引用ParentEntities的问题如果我有这样的事情:
Parent.java:
Parent.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.
好吧,到目前为止,everthings很好。但是当谈到从Java使用这个参考时,我想,你可以做这样的事情。
@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).
但事实并非如此,你必须明确地将Parent设置为Child(我认为,框架本身可能会自行完成)。
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:
Parent.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:
根据快速回复,我能够通过在Reference-Owning Entity上使用@JoinColumn来解决这个问题。如果我们从上面采取例子,我做了......喜欢这个:
Parent.java:
Parent.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.
谢谢你的答案。
5 个解决方案
#1
13
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 mappedBy
in the Parent
annotation.
在双向关系中,存在关系的“拥有”和“非拥有”方面。因为您的案例中的拥有方是在Child上,所以您需要在那里设置关系以使其保持不变。拥有方通常由您指定@JoinColumn的位置决定,但它看起来并不像您正在使用该注释,因此可能是因为您在Parent注释中使用了mappedBy这一事实。
You can read a lot more about this here.
你可以在这里阅读更多相关内容。
#2
3
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.
请注意,应用程序负责维护运行时关系的一致性 - 例如,确保在应用程序更新时双向关系的“一”和“多”方彼此一致运行时的关系。
#3
1
It still seems to be the case. In parent Entity
you can have something like
情况似乎仍然如此。在父实体中你可以有类似的东西
@PrePersist
private void prePersist() {
children.forEach( c -> c.setParent(this));
}
in order to avoid repeating code for setting child/parent relationship elsewhere in code.
为了避免重复代码在代码中的其他地方设置子/父关系。
#4
1
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列,在DB中具有外键约束。
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 @JoinColumn
to get it to work:
对于其他可能遇到此问题的人来说,我们最终发现的是我们必须使用@JoinColumn的另一个属性来使其工作:
@JoinColumn(name="paren_id", nullable=false)
#5
0
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.
在这里使用父对象做你想做的事情然后提交,这也适用于类似的情况。
#1
13
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 mappedBy
in the Parent
annotation.
在双向关系中,存在关系的“拥有”和“非拥有”方面。因为您的案例中的拥有方是在Child上,所以您需要在那里设置关系以使其保持不变。拥有方通常由您指定@JoinColumn的位置决定,但它看起来并不像您正在使用该注释,因此可能是因为您在Parent注释中使用了mappedBy这一事实。
You can read a lot more about this here.
你可以在这里阅读更多相关内容。
#2
3
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.
请注意,应用程序负责维护运行时关系的一致性 - 例如,确保在应用程序更新时双向关系的“一”和“多”方彼此一致运行时的关系。
#3
1
It still seems to be the case. In parent Entity
you can have something like
情况似乎仍然如此。在父实体中你可以有类似的东西
@PrePersist
private void prePersist() {
children.forEach( c -> c.setParent(this));
}
in order to avoid repeating code for setting child/parent relationship elsewhere in code.
为了避免重复代码在代码中的其他地方设置子/父关系。
#4
1
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列,在DB中具有外键约束。
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 @JoinColumn
to get it to work:
对于其他可能遇到此问题的人来说,我们最终发现的是我们必须使用@JoinColumn的另一个属性来使其工作:
@JoinColumn(name="paren_id", nullable=false)
#5
0
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.
在这里使用父对象做你想做的事情然后提交,这也适用于类似的情况。