Add objects to association in OnPreInsert, OnPreUpdate
Posted
by Dmitriy Nagirnyak
on Stack Overflow
See other posts from Stack Overflow
or by Dmitriy Nagirnyak
Published on 2010-05-14T08:21:48Z
Indexed on
2010/05/20
22:40 UTC
Read the original article
Hit count: 535
Hi,
I have an event listener (for Audit Logs) which needs to append audit log entries to the association of the object:
public Company : IAuditable {
// Other stuff removed for bravety
IAuditLog IAuditable.CreateEntry() {
var entry = new CompanyAudit();
this.auditLogs.Add(entry);
return entry;
}
public virtual IEnumerable<CompanyAudit> AuditLogs {
get { return this.auditLogs }
}
}
The AuditLogs
collection is mapped with cascading:
public class CompanyMap : ClassMap<Company> {
public CompanyMap() {
// Id and others removed fro bravety
HasMany(x => x.AuditLogs).AsSet()
.LazyLoad()
.Access.ReadOnlyPropertyThroughCamelCaseField()
.Cascade.All();
}
}
And the listener just asks the auditable object to create log entries so it can update them:
internal class AuditEventListener : IPreInsertEventListener, IPreUpdateEventListener {
public bool OnPreUpdate(PreUpdateEvent ev) {
var audit = ev.Entity as IAuditable;
if (audit == null)
return false;
Log(audit);
return false;
}
public bool OnPreInsert(PreInsertEvent ev) {
var audit = ev.Entity as IAuditable;
if (audit == null)
return false;
Log(audit);
return false;
}
private static void LogProperty(IAuditable auditable) {
var entry = auditable.CreateAuditEntry();
entry.CreatedAt = DateTime.Now;
entry.Who = GetCurrentUser(); // Might potentially execute a query.
// Also other information is set for entry here
}
}
The problem with it though is that it throws TransientObjectException
when commiting the transaction:
NHibernate.TransientObjectException : object references an unsaved transient instance - save the transient instance before flushing. Type: CompanyAudit, Entity: CompanyAudit
at NHibernate.Engine.ForeignKeys.GetEntityIdentifierIfNotUnsaved(String entityName, Object entity, ISessionImplementor session)
at NHibernate.Type.EntityType.GetIdentifier(Object value, ISessionImplementor session)
at NHibernate.Type.ManyToOneType.NullSafeSet(IDbCommand st, Object value, Int32 index, Boolean[] settable, ISessionImplementor session)
at NHibernate.Persister.Collection.AbstractCollectionPersister.WriteElement(IDbCommand st, Object elt, Int32 i, ISessionImplementor session)
at NHibernate.Persister.Collection.AbstractCollectionPersister.PerformInsert(Object ownerId, IPersistentCollection collection, IExpectation expectation, Object entry, Int32 index, Boolean useBatch, Boolean callable, ISessionImplementor session)
at NHibernate.Persister.Collection.AbstractCollectionPersister.Recreate(IPersistentCollection collection, Object id, ISessionImplementor session)
at NHibernate.Action.CollectionRecreateAction.Execute()
at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
at NHibernate.Engine.ActionQueue.ExecuteActions()
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()
As the cascading is set to All I expected NH to handle this. I also tried to modify the collection using state
but pretty much the same happens.
So the question is what is the last chance to modify object's associations before it gets saved?
Thanks,
Dmitriy.
© Stack Overflow or respective owner