[英]How do I properly cascade save a one-to-one, bidirectional relationship on primary key in Hibernate 3.6
I have an one-to-one, bidirectional entity relationship with shared keys. 我与共享密钥有一对一的双向实体关系。 When I attempt to save the owner of the association I get a "null id generated" exception against the owned side of the relationship.
当我尝试保存关联的所有者时,我得到了一个“null id generated”异常,对照关系的拥有方。 I am utilizing hibernate-entitymanager and using spring for transaction management.
我正在利用hibernate-entitymanager并使用spring进行事务管理。
Owning Entity 拥有实体
@Entity
@Table(name = "lead")
public class Lead
{
private Long leadId;
private LeadAffiliate leadAffiliate;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getLeadId()
{
return leadId;
}
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
public LeadAffiliate getLeadAffiliate()
{
return leadAffiliate;
}
}
Owned Entity 拥有实体
@Entity
@Table(name = "lead_affiliate")
public class LeadAffiliate
{
private Long leadId;
private Lead lead;
@Id
public Long getLeadId()
{
return leadId;
}
@MapsIdmappedBy = "leadAffiliate")
@OneToOne(cascade = CascadeType.All)
@PrimaryKeyJoinColumn
@JoinColumn(name = "lead_id")
public Lead getLead()
{
return lead;
}
}
and the code below is being used to save the entity: 并且以下代码用于保存实体:
LeadAffiliate aff = new LeadAffiliate();
aff.setLead(lead);
lead.setLeadAffiliate(aff);
em.persist(lead);
This all works perfectly fine in hibernate 3.5.0-Final. 这一切在hibernate 3.5.0-Final中完全正常。 When attempting to upgrade to 3.5.6-Final or 3.6.0.Final is when I start getting the "null id generated for LeadAffiliate" error:
当尝试升级到3.5.6-Final或3.6.0.Final时,我开始得到“为LeadAffiliate生成的空id”错误:
javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: null id generated for:class com.sellingsource.bizdev.entities.LeadAffiliate
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:678)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy152.persist(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy120.persist(Unknown Source)
at com.sellingsource.common.dao.JpaGenericDao.create(JpaGenericDao.java:38)
... 64 more
Caused by: org.hibernate.id.IdentifierGenerationException: null id generated for:class com.sellingsource.bizdev.entities.LeadAffiliate
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:799)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:791)
at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:48)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:450)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:282)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672)
... 77 more
As an aside, I am not sure that the annotations on Lead Affiliate were quite right to begin with. 顺便说一句,我不确定Lead Affiliate的注释是否适合开始。 They worked, but seemed kind of kludgey.
他们工作,但似乎有点kludgey。 So I have since changed them to:
所以我后来改为:
@Entity
@Table(name = "lead_affiliate")
public class LeadAffiliate
{
private Long leadId;
private Lead lead;
@Id
@GenericGenerator(name = "foreign", strategy = "foreign", parameters = {
@org.hibernate.annotations.Parameter(name = "property", value="lead")
})
@GeneratedValue(generator = "foreign")
public Long getLeadId()
{
return leadId;
}
@OneToOne(mappedBy = "leadAffiliate")
@PrimaryKeyJoinColumn
public Lead getLead()
{
return lead;
}
}
However, with these changes I get the same result. 但是,通过这些更改,我得到了相同的结果。 (Works in 3.5.0 but not 3.5.6 or 3.6.0)
(适用于3.5.0但不适用3.5.6或3.6.0)
Is there a new way I need to be doing this or is this a bug? 有没有新方法我需要这样做或这是一个错误? My concern is that my code is currently working because of a bug :/.
我担心的是我的代码目前正在运行,因为有一个bug:/。
Specification says that derived entity should be the owning side of the relationship: 规范说派生实体应该是关系的拥有方:
2.4.1 Primary Keys Corresponding to Derived Identities
2.4.1对应于派生身份的主键
The identity of an entity may be derived from the identity of another entity (the "parent" entity) when the former entity (the "dependent" entity) is the owner of a many-to-one or one-to-one relationship to the parent entity and a foreign key maps the relationship from dependent to parent.
当前实体(“从属”实体)是多对一或一对一关系的所有者时,实体的身份可以从另一个实体(“父”实体)的身份派生。父实体和外键将关系从依赖映射到父。
In your case LeadAffiliate
is derived, so it should be the owner, when Lead
should be marked as non-owning side by mappedBy
. 在您的情况下,
LeadAffiliate
是派生的,因此它应该是所有者,当Lead
应该被mappedBy
标记为非拥有方。 The following works in both 3.5.0 and 3.5.6: 以下适用于3.5.0和3.5.6:
public class Lead {
@Id @GeneratedValue
private Long leadId;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "lead")
private LeadAffiliate leadAffiliate;
...
}
. 。
public class LeadAffiliate {
@Id
private Long leadId;
@OneToOne @MapsId
private Lead lead;
...
}
My answer won't explain why things are working with Hibernate 3.5.0-Final but don't with 3.5.6-Final or 3.6.0.Final (and you should report this, I call this a regression). 我的答案不能解释为什么事情正在使用Hibernate 3.5.0-Final,但不能使用3.5.6-Final或3.6.0.Final(你应该报告这个,我称之为回归)。
Anyway, derived identifiers are much better supported in JPA 2.0, in a standard way, and in your case, I think you could simply annotate your OneToOne
relation with an Id
annotation. 无论如何,JPA 2.0以标准方式更好地支持派生标识符,在您的情况下,我认为您可以使用
Id
注释简单地注释OneToOne
关系。
Update: As underlined by axtavt, when using a derived identifier, the "dependent" entity must be the owner of the relationship. 更新:如axtavt所示,当使用派生标识符时,“依赖”实体必须是关系的所有者。 So the full mapping for the dependent entity would be:
因此,依赖实体的完整映射将是:
@Entity
@Table(name = "lead_affiliate")
public class LeadAffiliate {
private Lead lead;
@Id
@OneToOne
@JoinColumn(name="FK")
public Lead getLead() {
return lead;
}
}
And the "parent" entity: 而“父母”实体:
@Entity
@Table(name = "lead")
public class Lead {
private Long leadId;
private LeadAffiliate leadAffiliate;
@Id @GeneratedValue(strategy = GenerationType.AUTO)
public Long getLeadId() {
return leadId;
}
@OneToOne(cascade = CascadeType.ALL, mappedBy="lead")
public LeadAffiliate getLeadAffiliate() {
return leadAffiliate;
}
}
This is a valid JPA 2.0 mapping, and works with EclipseLink . 这是一个有效的JPA 2.0映射, 可与EclipseLink一起使用 。 However, Hibernate doesn't like it and won't instantiate the
EntityManagerFactory
(dammit!). 但是,Hibernate不喜欢它,也不会实例化
EntityManagerFactory
(该死!)。
As workaround, you'll have to use the solution suggested by axtavt ie to declare a primary key attribute as well as the relationship attribute and to use MapsId
on the relationship attribute. 作为解决方法,您将必须使用axtavt建议的解决方案,即声明主键属性以及关系属性,并在关系属性上使用
MapsId
。
But the above should work, there is IMO a bug in Hibernate (reported as HHH-5695 ). 但上面应该有效,有一个IMO在Hibernate中有一个错误(报告为HHH-5695 )。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.