We're currently having an issue that seems to be caused because the
Transaction.TransactionCompleted event is fired on a different thread
when using TransactionScope.
When NHibernate handles this event it closes the database connection.
However by this time another transaction and database call has already
started on the main thread. NHibernate has opened the connection for
the second call and expects it to remain open.
Detailed information is below.
Any comments would be appreciated.
Thanks,
Norman
Timeline:
MAIN THREAD: SessionFactory.OpenSession() // without passing a
connection
MAIN THREAD: using (new TransactionScope())
MAIN THREAD: SomeDatabaseWork();
MAIN THREAD: // NHibernate opens connection
MAIN THREAD: // NHibernate does database work
MAIN THREAD: // NHibernate closes connection
MAIN THREAD: // SomeDatabaseWork(); returns
MAIN THREAD: TransactionScope.Complete();
MAIN THREAD: TransactionScope.Dispose(); // from using
MAIN THREAD: using (new TransactionScope())
MAIN THREAD: MoreDatabaseWork();
MAIN THREAD: // NHibernate opens connection
ANOTHER THREAD: Transaction.TrasactionCompleted event fires
ANOTHER THREAD: Nhibernate event handler closes connection
MAIN THREAD: // NHibernate does database work --> EXCEPTION
HERE
Exception:
NHibernate.ADOException was unhandled by user code
Message="could not execute query\r\n[ select * from blah]"
Source="NHibernate"
SqlString="select * from blah"
StackTrace:
at NHibernate.Loader.Loader.DoList(ISessionImplementor session,
QueryParameters queryParameters)
at
NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor
session, QueryParameters queryParameters)
at NHibernate.Loader.Loader.List(ISessionImplementor session,
QueryParameters queryParameters, ISet`1 querySpaces, IType[]
resultTypes)
at
NHibernate.Loader.Criteria.CriteriaLoader.List(ISessionImplementor
session)
at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria,
IList results)
at NHibernate.Impl.CriteriaImpl.List(IList results)
at NHibernate.Impl.CriteriaImpl.List[T]()
at
NHibernate.Linq.Visitors.ImmediateResultsVisitor`1.GetElementList(MethodCallExpression
call, Int32 count)
at
NHibernate.Linq.Visitors.ImmediateResultsVisitor`1.HandleFirstOrDefaultCall(MethodCallExpression
call)
at
NHibernate.Linq.Visitors.ImmediateResultsVisitor`1.VisitMethodCall(MethodCallExpression
call)
at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression
exp)
at
NHibernate.Linq.Visitors.NHibernateExpressionVisitor.Visit(Expression
exp)
at
NHibernate.Linq.Visitors.ImmediateResultsVisitor`1.GetResults(MethodCallExpression
expr)
at
NHibernate.Linq.Visitors.RootVisitor.HandleImmediateResultsCall(MethodCallExpression
call)
at
NHibernate.Linq.Visitors.RootVisitor.VisitMethodCall(MethodCallExpression
expr)
at NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression
exp)
at
NHibernate.Linq.Visitors.NHibernateExpressionVisitor.Visit(Expression
exp)
at
NHibernate.Linq.Visitors.NHibernateQueryTranslator.TranslateInternal(Expression
expression)
at
NHibernate.Linq.Visitors.NHibernateQueryTranslator.Translate(Expression
expression, QueryOptions queryOptions)
at
NHibernate.Linq.NHibernateQueryProvider.TranslateExpression(Expression
expression)
at NHibernate.Linq.NHibernateQueryProvider.Execute(Expression
expression)
at
NHibernate.Linq.QueryProvider.System.Linq.IQueryProvider.Execute[T]
(Expression expression)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1
source)
at our code
at SyncInvokeGetGroupWellStates(Object , Object[] , Object[] )
at
System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object
instance, Object[] inputs, Object[]& outputs)
at
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&
rpc)
InnerException: System.InvalidOperationException
Message="Invalid operation. The connection is closed."
Source="System.Data.OracleClient"
StackTrace:
at
System.Data.OracleClient.OracleConnection.GetOpenInternalConnection()
at
System.Data.OracleClient.OracleConnection.get_ErrorHandle()
at
System.Data.OracleClient.OracleDataReader.FillColumnInfo()
at
System.Data.OracleClient.OracleDataReader..ctor(OracleCommand command,
OciStatementHandle statementHandle, String statementText,
CommandBehavior commandBehavior)
at
System.Data.OracleClient.OracleCommand.ExecuteReader(CommandBehavior
behavior)
at
System.Data.OracleClient.OracleCommand.ExecuteDbDataReader(CommandBehavior
behavior)
at
System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
at
NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
at NHibernate.Loader.Loader.GetResultSet(IDbCommand st,
Boolean autoDiscoverTypes, Boolean callable, RowSelection selection,
ISessionImplementor session)
at NHibernate.Loader.Loader.DoQuery(ISessionImplementor
session, QueryParameters queryParameters, Boolean returnProxies)
at
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor
session, QueryParameters queryParameters, Boolean returnProxies)
at NHibernate.Loader.Loader.DoList(ISessionImplementor
session, QueryParameters queryParameters)
InnerException:
Possible Workarounds:
1. Provide NHibernate with a connection when opening a session; or
2. Create a TransactionScope for duration of session (not ideal)
I've raised a Jira (NH-2176) for this and provided a failing unit
test:
Perhaps try the code I pasted into my issue and see what happens ...
http://groups.google.com/group/nhusers/browse_thread/thread/de1e4fc825b41a03
Option 2, do you mean create a new session for each transaction? That
is a good idea to me. I have been unable to use the same session, as
randomly the session decides it cannot disconnect as the transaction
has not been commited.
I think the best solution is to always use a session per transaction.
That will avoid most of the issues. But I still find I get the
occasional exception from multiple threads hitting
StatefulPersistenceContext.AfterTransactionCompletion. I put a lock in
SessionImpl.AfterTransactionCompletion which fixed that. Although I
would prefer not to modify the source code .... any ideas?
On Apr 15, 10:20 pm, Iain <iain.robe...@gmail.com> wrote:
> I think I am having the same issue. I have noticed that I sometimes
> get an exception on another thread. The other thread seems to be setup
> by the distributed transaction.
>
> Perhaps try the code I pasted into my issue and see what happens ...http://groups.google.com/group/nhusers/browse_thread/thread/de1e4fc82...