简体   繁体   English

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

[英]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 )。

References 参考

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 具有共享主键的双向一对一关系的外键约束违规 - Foreign Key constraint violation with bidirectional one-to-one relationship with shared primary key 如何确保 hibernate 5 在与共享主键的一对一关系中以正确的顺序持续存在 - How to make sure hibernate 5 persists in the correct order in a one-to-one relationship with shared primary key 如何在非主键上使用休眠注释设置单向一对一关系? - how to set unidirectional one-to-one relationship using hibernate annotation on a non-primary key? 如何将嵌套的 JSON 保存到具有一对一关系且共享主键的实体中? - How to save nested JSON into entities with one-to-one relationship that shares primary key? 我如何 map 与 JPA(休眠)中的复合主键建立一对多关系? - How do I map a One To Many Relationship with Composite Primary Key in JPA (Hibernate)? 如何在双向中通过hibernate envers审核一对一关系? - How to Audit one-to-one relation through hibernate envers in bidirectional? 如何在不通过休眠中的共享主键以一对一关系插入子对象的情况下保存父实体? - How to save parent entity without inserting child in one to one relationship by shared primary key in hibernate? 双向一对一关系(mappedBy) - bidirectional one-to-one relationship (mappedBy) Hibernate中的双向一对一关系 - Bidirectional one-to-one relationships in Hibernate Hibernate One-To-One关系 - Hibernate One-To-One relationship
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM