我与共享密钥具有一对一的双向实体关系。当我尝试保存关联的所有者时,对于该关系的拥有方,我收到一个“生成的null ID”异常。我正在使用hibernate- entitymanager并使用spring进行事务管理。
所属实体
@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; } }
@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; } }
并且以下代码用于保存实体:
LeadAffiliate aff = new LeadAffiliate(); aff.setLead(lead); lead.setLeadAffiliate(aff); em.persist(lead);
在hibernate3.5.0-最终版中,这一切都可以正常工作。尝试升级到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
顺便说一句,我不确定关于Lead Affiliate的注解是否正确。他们工作了,但似乎有些k昧。因此,我将其更改为:
@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; } }
但是,通过这些更改,我得到了相同的结果。(仅适用于3.5.0,不适用于3.5.6或3.6.0)
我需要一种新的方式来执行此操作,还是这是一个错误?我担心的是我的代码由于//错误而正在运行。
规范说派生实体应该是关系的拥有方:
2.4.1对应于派生身份的主键 当前一个实体(“从属”实体)是与该实体多对一或一对一关系的所有者时,一个实体的身份可以从另一个实体(“父”实体)的身份派生。父实体和外键将关系从依赖关系映射到父关系。
2.4.1对应于派生身份的主键
当前一个实体(“从属”实体)是与该实体多对一或一对一关系的所有者时,一个实体的身份可以从另一个实体(“父”实体)的身份派生。父实体和外键将关系从依赖关系映射到父关系。
在您的情况下LeadAffiliate是派生的,因此应为所有者,何时Lead应由标记为非所有者mappedBy。以下在3.5.0和3.5.6中均适用:
LeadAffiliate
Lead
mappedBy
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; ... }