Nhibernate Flush causing Updates where there shoul

2019-03-02 07:17发布

问题:

I am using the Repo pattern, and I have set up tests to replicate my a HTTP request coming in and then causing dispose on a unit of work once a test has completed.

It appears that after executing a HQL statement, and then calling displose (which in turn calls flush) that it is causing an update across various elements.

Very bizzare - has anyone come across this before?

Here is my HQL statement and it's execution:

_session.CreateQuery("select distinct t from TaskEntity as t").List<T>()

I've pulled this back to it's simplest form - and note the HQL statement is not directly in the CreateQuery.

Here is the stack trace I am getting:

I

BM.Data.Informix.IfxParameterCollection.b(Int32 A_0)
IBM.Data.Informix.IfxParameterCollection.GetParameter(Int32 index)
System.Data.Common.DbParameterCollection.System.Collections.IList.get_Item(Int32 index)
NHibernate.Type.Int32Type.Set(IDbCommand rs, Object value, Int32 index)
NHibernate.Type.NullableType.NullSafeSet(IDbCommand cmd, Object value, Int32 index)
NHibernate.Type.NullableType.NullSafeSet(IDbCommand st, Object value, Int32 index, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.Dehydrate(Object id, Object[] fields, Object rowId, Boolean[] includeProperty, Boolean[][] includeColumns, Int32 table, IDbCommand statement, ISessionImplementor session, Int32 index)
NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session)
NHibernate.Action.EntityUpdateAction.Execute()
NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
NHibernate.Engine.ActionQueue.ExecuteActions()
NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
NHibernate.Impl.SessionImpl.Flush()
Case.Data.SQL.NHibernateUnitOfWork.Dispose() in C:\Projects\Case System\Dev\WorkingBranch\Src\Case.Data.SQL\NHibernateUnitOfWork.cs: line 46
Case.Domain.Tests.TaskServicesTests.TakeDown() in C:\Projects\Case System\Dev\WorkingBranch\Src\Case.Domain.Tests\TaskServicesTests.cs: line 40

回答1:

I faced a similar problem. I'll first tell you what causes this. When NHibernate fetches an entity from the DB it assigns values to it's props. There are few props that have null values in the DB but are not of Nullable type in the class definition. So NHibernate assigns them a default value eg. 0 for int, DateTime.MinValue for datetime etc. When you call commit on the transaction, NHibernate rechecks the values of properties with DB values and since props which should have had Null values now have a default value, NHibernate thinks that the values have been changed and causes an update.

Solution:

  1. Use nullable datatypes for your class props by post fixing them with ? but for me this is causing other problems.
  2. Map your properties as Not Null Types but this is not preferable in most cases.
  3. The solution that I am using: I am assigning default values to the props in the entity's constructor, so instead of saving Null values in the Db Nhibernate saves some default value and this stops the calls to unnecessary updates.

You may further google NHibernate ghostbuster for more research on this problem.



回答2:

NHibernate typically runs updates when it has transient or detached entities that it isn't sure about. That is, entities that it doesn't know if it has a parent for that manages it or if its not sure the entity is dirty. This is typically a symptom of a bad mapping somewhere (a missing Inverse on some parent) or you have no Version or Date column on your entities.