在Hibernate中更新join-subclass

时间:2014-01-27 13:14:27

标签: java mysql hibernate orm

我有一个基类A和一个子类B。当我在Spring表单中检索A的实例时,我想编辑实例A并将其更新为数据库中B的实例。 A和B都是数据库中的两个不同的表,但它们已使用joined-subclass进行映射。但是,当我尝试将A的实例转换为B并将其另存为B时,我会遇到以下异常:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing:A
at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:249)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:510)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:309)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:319)
at org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:294)
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:4037)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:527)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:234)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:163)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:228)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:100)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at org.hibernate.envers.synchronization.AuditProcess.doBeforeTransactionCompletion(AuditProcess.java:158)
at org.hibernate.envers.synchronization.AuditProcessManager$1.doBeforeTransactionCompletion(AuditProcessManager.java:62)
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:699)
at org.hibernate.engine.spi.ActionQueue.beforeTransactionCompletion(ActionQueue.java:321)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:613)
at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorImpl.beforeCompletion(SynchronizationCallbackCoordinatorImpl.java:122)
at org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:53)
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:435)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:85

A和B在数据库中共享相同的主键值。

有没有办法将A转换为B并将其另存为B。这是映射的代码:

<hibernate-mapping  package="db">
    <class name="Person" table="A">
        <id name="personId" >
            <generator class="identity"/>
        </id>
        <property name="forename" length="50" not-null="true" />
        <property name="middleName" length="50" />
        <property name="surname" length="50" not-null="true" />
        <property name="birthDate"/>
        <component name="address">
            <property name="street" length="50"  />
            <property name="town" length="50"  />
            <property name="county" length="50"  />
            <property name="postcode" length="10"  />
        </component>
        <property name="telephone" length="15" />
        <property name="updateTime" not-null="true"  />
        <property name="updatedBy" not-null="true"  />
    </class>
     <joined-subclass name="db.B" extends="A">
        <key column="personId" />
        <property name="employeeDescription" />
        // more properties
    </joined-subclass>
</hibernate-mapping>

这是A DAO的代码:

public class HibernateADAO {
     public void updateA(A a) {
         this.sessionFactory.getCurrentSession().merge(a);
     }
}

B DAO:

public class HibernateBDAO {
     public void updateB(B b) {
         this.sessionFactory.getCurrentSession().merge(b);
     }
}

这是我目前用来更新B的控制器代码的样式:

 // retrieve A from db (works fine).
 A a = retrieveFromDb();
 B b = new B(a);
 // set properties of b
 if (b.getPersonId() != null) {
     A a = (A) b;
     hibernateADao.update(a);
     hibernateBDao.update(b);
 } else {
    // create new instance of B, which will also create a new A in the database.
 }

1 个答案:

答案 0 :(得分:1)

我找到了解决问题的方法。首先,我必须使用Hibernate的B功能将createSQLQuery()插入数据库,以使用B中的主键值在数据库中创建A的实例({ {1}}已经在数据库中已经分配了PK值。)

完成后,我使用Hibernate A从数据库中检索了保存的B实例。然后,我设置返回的get()实例的更多属性的值。当我更新B的实例时,我使用了B而不是saveOrUpdate()。现在我有一个转换后的merge()实例,即使它以前是数据库中B类型的实例。

这是一个丑陋的黑客,但它确实有效。