@OneToMany 和复合主键?
我正在使用 Hibernate 和注释(在 spring 中),并且我有一个对象,它具有有序的多对一关系,其中一个子对象具有复合主键,其中一个组件是返回到的外键父对象的 id。
结构看起来像这样:
+=============+ +================+
| ParentObj | | ObjectChild |
+-------------+ 1 0..* +----------------+
| id (pk) |-----------------| parentId |
| ... | | name |
+=============+ | pos |
| ... |
+================+
我尝试了各种注释组合,但似乎都不起作用。这是我能想到的最接近的结果:
@Entity
public class ParentObject {
@Column(nullable=false, updatable=false)
@Id @GeneratedValue(generator="...")
private String id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER, cascade={CascadeType.ALL})
@IndexColumn(name = "pos", base=0)
private List<ObjectChild> attrs;
...
}
@Entity
public class ChildObject {
@Embeddable
public static class Pk implements Serializable {
@Column(nullable=false, updatable=false)
private String parentId;
@Column(nullable=false, updatable=false)
private String name;
@Column(nullable=false, updatable=false)
private int pos;
@Override
public String toString() {
return new Formatter().format("%s.%s[%d]", parentId, name, pos).toString();
}
...
}
@EmbeddedId
private Pk pk;
@ManyToOne
@JoinColumn(name="parentId")
private ParentObject parent;
...
}
经过长时间的实验,我得到了这个结果,其中我的大多数其他尝试都产生了由于各种原因而休眠甚至无法加载的实体。
更新:感谢大家的评论;我已经取得了一些进步。我做了一些调整,我认为它更接近了(我已经更新了上面的代码)。然而,现在问题出在插入上。父对象似乎保存得很好,但子对象没有保存,我能够确定的是,hibernate 没有填写子对象的(复合)主键的parentId 部分,所以我'我收到一个不唯一的错误:
org.hibernate.NonUniqueObjectException:
a different object with the same identifier value was already associated
with the session: [org.kpruden.ObjectChild#null.attr1[0]]
我正在自己的代码中填充 name
和 pos
属性,但我当然不知道父 ID,因为它尚未保存。关于如何说服 hibernate 填写此内容有什么想法吗?
谢谢!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
经过多次尝试和挫折后,我最终确定我不能完全做我想做的事。
最终,我继续为子对象提供了自己的合成密钥,并让 Hibernate 管理它。这并不理想,因为密钥几乎与其余数据一样大,但它有效。
After much experimentation and frustration, I eventually determined that I cannot do exactly what I want.
Ultimately, I went ahead and gave the child object its own synthetic key and let Hibernate manage it. It's a not ideal, since the key is almost as big as the rest of the data, but it works.
发现这个问题正在寻找其问题的答案,但它的答案并没有解决我的问题,因为我正在寻找
@OneToMany
,它不太适合我的表结构追赶。@ElementCollection
非常适合我的情况。但我认为它的一个陷阱是,它将整行关系视为唯一,而不仅仅是行 id。Found this question searching for the answer to it's problem, but it's answers didn't solve my problem, because I was looking for
@OneToMany
which isn't as good of a fit for the table structure I was going after.@ElementCollection
is the right fit in my case. One of the gotchas of it I believe though is that it looks at the entire row of relations as being unique, not just the rows id.看起来你已经非常接近了,我正在尝试在当前的系统中做同样的事情。我从代理键开始,但想删除它,转而使用由父项的 PK 和列表中的索引组成的复合主键。
我能够通过使用“外部”生成器获得从主表共享 PK 的一对一关系:
我想知道您是否可以添加 @GenericGenerator 和 @GenerateValue 来解决 Hibernate 不分配父级的问题插入期间新获得的 PK。
It seems that you got pretty close, and I am trying to do the same thing in my current system. I started with the surrogate key but would like to remove it in favor of a composite primary key consisting of the parent's PK and the index in the list.
I was able to get a one-to-one relationship that shares the PK from the master table by using a "foreign" generator:
I wonder if you could add the @GenericGenerator and @GeneratedValue to solve the problem of Hibernate not assigning the parent's newly acquired PK during insertion.
保存父对象后,您必须在子对象中显式设置parentId,以便子对象上的插入起作用。
After saving the Parent object, you have to explicitly set the parentId in the Child objects for the inserts on the Child objects to work.
经过三天的研究,我想我已经找到了解决方案,但说实话,我不喜欢它,而且它绝对可以改进。然而,它确实有效并解决了我们的问题。
这是您的实体构造函数,但您也可以在 setter 方法中执行此操作。
另外,我使用了 Collection 对象,但它应该与 List 相同或相似:
基本上,正如其他人建议的那样,我们必须首先手动设置所有子级的父级 id,然后再保存父级(以及所有子级)
After spending three days on this, I think I have found a solution, but to be honest, I don't like it and it can definitely be improved. However, it works and solves our problem.
Here is your entity constructor, but you could also do it in the setter method.
Also, I used a Collection object but it should be same or similar with List:
Basically, as someone else suggested, we must first manually set all the children's parent id before saving the parent (along with all children)
我一直在努力寻找答案,但找不到可行的解决方案。虽然我在父项中正确地使用了 OneToMany,在子项中正确地设置了 ManyToOne,但在父项保存期间,子项的密钥没有被分配,而是从父项自动生成的值。
我的问题通过在子实体(Java 类)中的 @ManyToOne 映射上方添加注释 javax.persistence.MapsId 得到解决,
这是 @Pascal Thivent 回答的内容(于 2010 年 4 月 10 日 1:40 回答)
请参阅本线程前面他的帖子中的示例代码片段。
谢谢,
PJR。
I was badly looking for an answer but couldn't find a working solution. Though I had the OneToMany in parent correctly and ManyToOne in child correctly, during parent's save, child's key was not getting assigned, the auto-generated value from parent.
My problem was fixed upon adding an annotation javax.persistence.MapsId above the @ManyToOne mapping in the child entity (Java class)
This is on top of what was answered by @Pascal Thivent (answered on Apr 10 '10 at 1:40)
Please refer to the example code snippet in his post, earlier in this thread.
Thanks,
PJR.
Manning 的书 Java Persistence with Hibernate 在第 7.2 节中提供了一个示例,概述了如何执行此操作。幸运的是,即使您没有这本书,您也可以通过下载 买者自负示例项目(直接链接此处< /a>)并检查
auction.model
包中的Category
和CategorizedItem
类。我还将总结下面的关键注释。如果仍然不行,请告诉我。
父对象:
子对象:
The Manning book Java Persistence with Hibernate has an example outlining how to do this in Section 7.2. Fortunately, even if you don't own the book, you can see a source code example of this by downloading the JPA version of the Caveat Emptor sample project (direct link here) and examining the classes
Category
andCategorizedItem
in theauction.model
package.I'll also summarize the key annotations below. Do let me know if it's still a no-go.
ParentObject:
ChildObject:
您应该将
ParentObject
引用合并到ChildObject.Pk
中,而不是分别映射parent 和parentId:(与问题无关的getter、setter、Hibernate 属性以及省略的成员访问关键字)
在
ParentObject
中,您只需输入@OneToMany(mappedBy="id.parent")
即可。You should incorporate the
ParentObject
reference just intoChildObject.Pk
rather than map parent and parentId separately:(getters, setters, Hibernate attributes not related to problem and member access keywords omitted)
In
ParentObject
you then just put@OneToMany(mappedBy="id.parent")
and it works.首先,在
ParentObject
中,“修复”应设置为“parent”
的mappedBy
属性。另外(但这可能是一个拼写错误)添加一个@Id
注释:然后,在
ObjectChild
中,向添加一个
:name
属性组合键中的 objectIdAND 还将
insertable = false, updatable = false
添加到@JoinColumn
因为我们正在重复该实体映射中的parentId
列。通过这些更改,坚持并读取实体对我来说效果很好(使用 Derby 进行了测试)。
Firstly, in the
ParentObject
, "fix" themappedBy
attribute that should be set to"parent"
. Also (but this is maybe a typo) add an@Id
annotation:Then, in
ObjectChild
, add aname
attribute to theobjectId
in the composite key:AND also add
insertable = false, updatable = false
to the@JoinColumn
because we are repeating theparentId
column in the mapping of this entity.With these changes, persisting and reading the entities is working fine for me (tested with Derby).