我有一个基类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.
}
答案 0 :(得分:1)
我找到了解决问题的方法。首先,我必须使用Hibernate的B
功能将createSQLQuery()
插入数据库,以使用B
中的主键值在数据库中创建A
的实例({ {1}}已经在数据库中已经分配了PK值。)
完成后,我使用Hibernate A
从数据库中检索了保存的B
实例。然后,我设置返回的get()
实例的更多属性的值。当我更新B
的实例时,我使用了B
而不是saveOrUpdate()
。现在我有一个转换后的merge()
实例,即使它以前是数据库中B
类型的实例。
这是一个丑陋的黑客,但它确实有效。