【问题标题】:Hibernate @OneToOne mapping with reverse reference and CascadeType.ALL on owner does not persist the childHibernate @OneToOne 映射与反向引用和所有者上的 CascadeType.ALL 不会持久化孩子
【发布时间】:2011-03-08 00:55:46
【问题描述】:

我们有以下实体关系。 User 是父实体。DistrictUserDetail 是子实体。

@Entity
@Table(name="USERS")
public class User implements Serializable {

@Id
@Column(name="ID", nullable=false)
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String id;

    @OneToOne(cascade= {CascadeType.ALL})
    @PrimaryKeyJoinColumn(name="ID", referencedColumnName="USER_ID")
    public DistrictUserDetail districtUserDetail;

    ... other properties..

这是父实体。 子实体主键是用户实体的外键,我们将其关键属性定义为:

@Entity
@Table(name="DISTRICT_USER_DETAIL")
public class DistrictUserDetail implements Serializable{



@Id  
@Column(name="USER_ID")  
@GeneratedValue(generator="foreign")   
@GenericGenerator(name="foreign", strategy = "foreign",   
parameters={@Parameter(name="property",value="user")})  
protected String userId;  

@OneToOne(mappedBy="districtUserDetail")  
User user; 

    ... other properties

所以,当我们创建一个新用户,并创建一个新的 DistrictUser,并将 DistrictUser 设置为用户并保存用户时,我们期望用户被保存,由于 cascadeAll,DistrictUser 也被保存。

这是我们的测试:

public void testSaveUserWithDistrictUserDetails() throws Exception {
    User user = new User();
    user.setFirstName("John");
    user.setLastName("Doe");
    user.setUserName("U11111");


    DistrictUserDetail userDetail = new DistrictUserDetail();

    userDetail.setIsLoginAllowed(Boolean.TRUE);
    userDetail.setIsSuperintendent(Boolean.TRUE);

    user.setDistrictUserDetail(userDetail);

    User newUser = dao.save(user);

    assertTrue(newUser!=null);
    assertTrue(newUser.getId()!=null);
}

但是我们遇到下面的hibernate异常:

Caused by: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property: user
at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:44)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:99)
at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:315)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:283)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:238)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:688)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:670)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:245)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:269)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:217)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:170)
at org.hibernate.engine.Cascade.cascade(Cascade.java:131)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:352)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:283)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:238)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:85)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:678)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:662)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:666)
at org.springframework.orm.hibernate3.HibernateTemplate$23.doInHibernate(HibernateTemplate.java:817)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
... 49 more

如果 User 实体可以调用 DistrictUserDetail 的保存,那为什么 DistrictUserDetail 不能看到父 User(及其新 id)并使用它来保存它。

我们使用的是休眠版本:3.2.7.ga 底层数据库是:MySQL

任何帮助将不胜感激。 谢谢

【问题讨论】:

    标签: mysql hibernate mapping one-to-one


    【解决方案1】:

    userDeatil.usernull,这就是异常所抱怨的。

    我建议删除该属性并且不存在双向关系。否则user.setDistrictUserDetail()也需要设置user属性。

    【讨论】:

    • 正如帖子的标题所示,我们希望建立双向关系。没有它它可以工作,但我们的用例确实需要它。此外,我们尝试在调用 dao.save(user) 之前在 userDetail 上设置用户对象,但这并没有改变结果或错误。至于 userDetail.user 为空,我知道这一点。这就是我问另一个问题的原因:如果用户对象可以将 userDetail 识别为要合并/持久的级联对象,那么 userDetail 不应该将用户识别为父/所有者吗?
    • 不,因为双向关系不是这样工作的。只有拥有方(没有mappedBy 的一方)可以级联到另一方。其他选项包括不为 userDetail 的密钥使用生成器,或使用 @Embedded
    【解决方案2】:

    您应该像这样将 OneToOne 的可选属性设置为 false:

    @OneToOne(mappedBy="districtUserDetail", optional = false)  
    User user; 
    

    此外,您当然应该将 DistrictUserDetail.user 设置为非空实体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-02
      • 2021-08-01
      • 1970-01-01
      • 2018-05-20
      相关资源
      最近更新 更多