java - 如何在 Hibernate 3.6 中正确级联保存主键上的一对一双向关系

标签 java hibernate orm jpa jpa-2.0

我与共享 key 建立了一对一的双向实体关系。当我尝试保存关联的所有者时,我得到一个针对关系拥有方的“生成空 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);

这一切在 hibernate 3.5.0-Final 中都可以正常工作。尝试升级到 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 上的注释一开始就完全正确。他们工作,但似乎有点笨拙。所以我把它们改成了:

@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 Primary Keys Corresponding to Derived Identities

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.

在你的情况下 LeadAffiliate 是派生的,所以它应该是所有者,当 Lead 应该由 mappedBy 标记为非拥有方.以下适用于 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; 

    ...
}

关于java - 如何在 Hibernate 3.6 中正确级联保存主键上的一对一双向关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4027623/

相关文章:

java - if语句的使用

java - eager fetch 在 hibernate 中执行左连接

hibernate - 这些 @Table(uniqueConstraints) 和 @Table(indexes) 注释是否相同?

sql - django orm queryset - 如何执行sql查询MIN/MAX FILTER

python - 独立应用程序上的 Django ORM

java - 使用 joda-time 转换时间字符串

java - 在 Java 中防止 NullPointerException

java - Spring Security Java 配置问题

java - join fetch 在 Hibernate 查询语言中不起作用

php - Propel - 检索所有表