Hi,
I have a wierd hibernate exception,
Code:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: AbstractAuditRecord
that seems to be caused by Hibernate generating the wrong statements when doing an update of the record.
I have the following tables: AbstractAuditRecord, IGTExport and IGTExportAuditRecord. The code works fine when doing inserts of IGTExport, but on update, it tries to update existing audit info when I would like to insert rows rather.
Code:
Hibernate: update CFdb.dbo.IGTExport set SourceBankAccountId=?,DestinationBankAccountId=?, Passed=?, ErrorCodeID=?, ExportBID=?, ExternalSeqNo=?, UserReference=?, Amount=?, Remainder=?, DateStamp=? where IGTExportId=?
Hibernate: update AbstractAuditRecord set operationDate=?, message=?, operationKey=?, Username=?, AuditRecordActionTypeID=? where id=?
Hibernate: update AbstractAuditRecord set operationDate=?, message=?, operationKey=?, Username=?, AuditRecordActionTypeID=? where id=?
Hibernate: insert into IGTExportAuditRecord (IGTExportId, AbstractAuditRecordId) values (?, ?)
This is then throwing the TransientObjectException
Relevant Tables:
Code:
AbstractAuditRecord (AbstractAuditRecordID, parent_log_id,...)
IGTExportAuditRecord(IGTExportAuditRecordID,AbstractAuditRecordID)
IGTExport (IGTExportID, ....)
Relevant Mapping Files:
AbstractAuditRecord:
Code:
...
<set cascade="persist, delete-orphan" lazy="false"
name="childAuditRecords" sort="unsorted">
<key column="parent_log_id" />
<one-to-many
class="AbstractAuditRecord" />
</set>
<many-to-one name="parentAuditRecord" lazy="false"
column="parent_log_id"
class="AbstractAuditRecord"
cascade="all" />
...
Code:
IGTExport:
...
<set name="entityAuditRecords" lazy="true" table="IGTExportAuditRecord" inverse="false"
cascade="all-delete-orphan" >
<key>
<column name="IGTExportId" not-null="true" unique="true" />
</key>
<many-to-many column="AbstractAuditRecordId" unique="true" class="AbstractAuditRecord"/>
</set>
...
So a AbstractAuditRecord has many child records, and zero or one parent records.
The auditable table has one or more AbstractAuditRecords.
In the Hibernate Interceptor onSave() we have the following code:
Code:
AbstractAuditRecord parentAuditRecord = new AbstractAuditRecord()
...
...
AbstractAuditRecord childAuditRecord = new AbstractAuditRecord();
...
childAuditRecord.setParentAuditRecord(parentAuditRecord);
auditable.getEntityAuditRecords().add(childAuditRecord)
The idea being we are creating a ParentAuditRecord, then the childAuditRecord, then adding the childAuditRecord to the auditable interface (which IGTExport implements). When
Code:
update(Igtexport)
is called, it should update itself, and cascade the relationship to the childAuditRecord, and then the ParentAuditRecord.
A parentAuditRecord may have many childAuditRecords, with the parentAuditRecord actually controlled by a stack.
I could be thinking about this wrong, and it may be impossible to not link IGTExport with the previous entries in the join many-to-many table. Is there a better alternative? I've tried using afterTransactionCompletion() to save the childAuditRecords, and also tried saving the parentAuditRecord.