diff --git a/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs b/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs index 8aa9d2497d4..51a4560c190 100644 --- a/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs +++ b/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs @@ -192,7 +192,7 @@ public void SuppliedConnection() session.Flush(); Release(session); - originalConnection.Close(); + sessions.ConnectionProvider.CloseConnection(originalConnection); Done(); } @@ -245,4 +245,4 @@ public void ConnectionMaintanenceDuringFlush() Done(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DialectTest/DialectFixture.cs b/src/NHibernate.Test/DialectTest/DialectFixture.cs index 7a4814b3d52..45c393595ae 100644 --- a/src/NHibernate.Test/DialectTest/DialectFixture.cs +++ b/src/NHibernate.Test/DialectTest/DialectFixture.cs @@ -159,10 +159,13 @@ public void CurrentTimestampSelection() sessions.ConnectionProvider.Configure(conf.Properties); IDriver driver = sessions.ConnectionProvider.Driver; - using (IDbConnection connection = sessions.ConnectionProvider.GetConnection()) + var connection = sessions.ConnectionProvider.GetConnection(); + try { - IDbCommand statement = driver.GenerateCommand(CommandType.Text, new SqlString(dialect.CurrentTimestampSelectString), - new SqlType[0]); + IDbCommand statement = driver.GenerateCommand( + CommandType.Text, + new SqlString(dialect.CurrentTimestampSelectString), + new SqlType[0]); statement.Connection = connection; using (IDataReader reader = statement.ExecuteReader()) { @@ -170,7 +173,10 @@ public void CurrentTimestampSelection() Assert.That(reader[0], Is.InstanceOf()); } } + finally + { + sessions.ConnectionProvider.CloseConnection(connection); + } } - } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/DriverTest/FirebirdClientDriverFixture.cs b/src/NHibernate.Test/DriverTest/FirebirdClientDriverFixture.cs index 4d389aec612..4f088f44130 100644 --- a/src/NHibernate.Test/DriverTest/FirebirdClientDriverFixture.cs +++ b/src/NHibernate.Test/DriverTest/FirebirdClientDriverFixture.cs @@ -16,24 +16,25 @@ public class FirebirdClientDriverFixture public void ConnectionPooling_OpenThenCloseThenOpenAnotherOne_OnlyOneConnectionIsPooled() { MakeDriver(); - var connection1 = MakeConnection(); - var connection2 = MakeConnection(); + using (var connection1 = MakeConnection()) + using (var connection2 = MakeConnection()) + { + connection1.Open(); + VerifyCountOfEstablishedConnectionsIs(1); - //open first connection - connection1.Open(); - VerifyCountOfEstablishedConnectionsIs(1); + //return it to the pool + connection1.Close(); + VerifyCountOfEstablishedConnectionsIs(1); - //return it to the pool - connection1.Close(); - VerifyCountOfEstablishedConnectionsIs(1); + //open the second connection + connection2.Open(); + VerifyCountOfEstablishedConnectionsIs(1); - //open the second connection - connection2.Open(); - VerifyCountOfEstablishedConnectionsIs(1); + //return it to the pool + connection2.Close(); - //return it to the pool - connection2.Close(); - VerifyCountOfEstablishedConnectionsIs(1); + VerifyCountOfEstablishedConnectionsIs(1); + } } [Test] diff --git a/src/NHibernate.Test/Legacy/FooBarTest.cs b/src/NHibernate.Test/Legacy/FooBarTest.cs index e60062b0085..0e11e3b5930 100644 --- a/src/NHibernate.Test/Legacy/FooBarTest.cs +++ b/src/NHibernate.Test/Legacy/FooBarTest.cs @@ -4978,20 +4978,27 @@ public void AutoFlushCollections() public void UserProvidedConnection() { IConnectionProvider prov = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties); - ISession s = sessions.OpenSession(prov.GetConnection()); - ITransaction tx = s.BeginTransaction(); - s.CreateQuery("from foo in class NHibernate.DomainModel.Fo").List(); - tx.Commit(); + var conn = prov.GetConnection(); + try + { + ISession s = sessions.OpenSession(conn); + ITransaction tx = s.BeginTransaction(); + s.CreateQuery("from foo in class NHibernate.DomainModel.Fo").List(); + tx.Commit(); - IDbConnection c = s.Disconnect(); - Assert.IsNotNull(c); + IDbConnection c = s.Disconnect(); + Assert.IsNotNull(c); - s.Reconnect(c); - tx = s.BeginTransaction(); - s.CreateQuery("from foo in class NHibernate.DomainModel.Fo").List(); - tx.Commit(); - Assert.AreSame(c, s.Close()); - c.Close(); + s.Reconnect(c); + tx = s.BeginTransaction(); + s.CreateQuery("from foo in class NHibernate.DomainModel.Fo").List(); + tx.Commit(); + Assert.AreSame(c, s.Close()); + } + finally + { + prov.CloseConnection(conn); + } } [Test] diff --git a/src/NHibernate.Test/Linq/LinqReadonlyTestsContext.cs b/src/NHibernate.Test/Linq/LinqReadonlyTestsContext.cs index 04ec017e668..d6a195b2597 100644 --- a/src/NHibernate.Test/Linq/LinqReadonlyTestsContext.cs +++ b/src/NHibernate.Test/Linq/LinqReadonlyTestsContext.cs @@ -71,7 +71,8 @@ private void ExecuteScriptFile(Configuration configuration, string scripFileName var file = new FileInfo(scripFileName); string script = file.OpenText().ReadToEnd().Replace("GO", ""); var connectionProvider = ConnectionProviderFactory.NewConnectionProvider(configuration.GetDerivedProperties()); - using (var conn = connectionProvider.GetConnection()) + var conn = connectionProvider.GetConnection(); + try { if (conn.State == ConnectionState.Closed) { @@ -83,6 +84,10 @@ private void ExecuteScriptFile(Configuration configuration, string scripFileName command.ExecuteNonQuery(); } } + finally + { + connectionProvider.CloseConnection(conn); + } } [TearDown] @@ -143,4 +148,4 @@ private void CreateTestData(ISessionFactory sessionFactory) } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH2420/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2420/Fixture.cs index f42ec01ce93..34f4ab22e41 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2420/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2420/Fixture.cs @@ -90,7 +90,7 @@ public void ShouldBeAbleToReleaseSuppliedConnectionAfterDistributedTransaction() // fires *after* the transaction is committed and so it doesn't affect the success // of the transaction. - Assert.That(s.IsConnected, Is.False); + Assert.That(() => s.IsConnected, Is.False.After(500, 100)); Assert.That(((ISessionImplementor)s).ConnectionManager.IsConnected, Is.False); Assert.That(((ISessionImplementor)s).IsClosed, Is.True); } diff --git a/src/NHibernate.Test/NHSpecificTest/UserTypeFixture.cs b/src/NHibernate.Test/NHSpecificTest/UserTypeFixture.cs index 1b92a888614..7af363bab3d 100644 --- a/src/NHibernate.Test/NHSpecificTest/UserTypeFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/UserTypeFixture.cs @@ -39,22 +39,27 @@ public void InsertNull() // manually read from the db IConnectionProvider provider = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties); IDbConnection conn = provider.GetConnection(); - IDbCommand cmd = conn.CreateCommand(); - cmd.Connection = conn; - cmd.CommandText = "select * from usertype"; + try + { + IDbCommand cmd = conn.CreateCommand(); + cmd.Connection = conn; + cmd.CommandText = "select * from usertype"; - IDataReader reader = cmd.ExecuteReader(); + IDataReader reader = cmd.ExecuteReader(); - while (reader.Read()) + while (reader.Read()) + { + Assert.AreEqual(5, reader[0]); + Assert.AreEqual(4, reader[1]); + Assert.AreEqual(DBNull.Value, reader[2]); + break; + } + } + finally { - Assert.AreEqual(5, reader[0]); - Assert.AreEqual(4, reader[1]); - Assert.AreEqual(DBNull.Value, reader[2]); - break; + provider.CloseConnection(conn); } - conn.Close(); - using (ISession s = OpenSession()) { s.Delete("from ClassWithNullColumns"); @@ -62,4 +67,4 @@ public void InsertNull() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/SystemTransactions/TransactionNotificationFixture.cs b/src/NHibernate.Test/SystemTransactions/TransactionNotificationFixture.cs index 92371d09257..b0c46371c08 100644 --- a/src/NHibernate.Test/SystemTransactions/TransactionNotificationFixture.cs +++ b/src/NHibernate.Test/SystemTransactions/TransactionNotificationFixture.cs @@ -161,13 +161,12 @@ public void ShouldNotifyAfterDistributedTransactionWithOwnConnection(bool doComm using (var tx = new TransactionScope()) { - IDbConnection ownConnection1 = sessions.ConnectionProvider.GetConnection(); - + var ownConnection = sessions.ConnectionProvider.GetConnection(); try { try { - s1 = sessions.OpenSession(ownConnection1, interceptor); + s1 = sessions.OpenSession(ownConnection, interceptor); s1.CreateCriteria().List(); } @@ -182,7 +181,7 @@ public void ShouldNotifyAfterDistributedTransactionWithOwnConnection(bool doComm } finally { - sessions.ConnectionProvider.CloseConnection(ownConnection1); + sessions.ConnectionProvider.CloseConnection(ownConnection); } } @@ -191,6 +190,5 @@ public void ShouldNotifyAfterDistributedTransactionWithOwnConnection(bool doComm Assert.That(interceptor.afterTransactionCompletionCalled, Is.EqualTo(1)); } - } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/TestCase.cs b/src/NHibernate.Test/TestCase.cs index 96232442a57..2ce5e14b807 100644 --- a/src/NHibernate.Test/TestCase.cs +++ b/src/NHibernate.Test/TestCase.cs @@ -207,14 +207,15 @@ protected virtual bool CheckDatabaseWasCleaned() private bool CheckConnectionsWereClosed() { - if (connectionProvider == null || !connectionProvider.HasOpenConnections) - { + if (connectionProvider == null) return true; - } - log.Error("Test case didn't close all open connections, closing"); + var hasOpenConnections = connectionProvider.HasOpenConnections; + if (hasOpenConnections) + log.Error("Test case didn't close all open connections, closing"); + connectionProvider.CloseAllConnections(); - return false; + return !hasOpenConnections; } private void Configure() @@ -275,7 +276,7 @@ public int ExecuteStatement(string sql) using (IConnectionProvider prov = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) { - IDbConnection conn = prov.GetConnection(); + var conn = prov.GetConnection(); try { diff --git a/src/NHibernate.Test/TransactionTest/TransactionNotificationFixture.cs b/src/NHibernate.Test/TransactionTest/TransactionNotificationFixture.cs index cc6965dcc1c..10c40294ae7 100644 --- a/src/NHibernate.Test/TransactionTest/TransactionNotificationFixture.cs +++ b/src/NHibernate.Test/TransactionTest/TransactionNotificationFixture.cs @@ -96,7 +96,8 @@ public void ShouldNotifyAfterTransactionWithOwnConnection(bool usePrematureClose var interceptor = new RecordingInterceptor(); ISession s; - using (IDbConnection ownConnection = sessions.ConnectionProvider.GetConnection()) + var ownConnection = sessions.ConnectionProvider.GetConnection(); + try { using (s = sessions.OpenSession(ownConnection, interceptor)) using (s.BeginTransaction()) @@ -108,9 +109,13 @@ public void ShouldNotifyAfterTransactionWithOwnConnection(bool usePrematureClose s.Close(); } } + finally + { + sessions.ConnectionProvider.CloseConnection(ownConnection); + } Assert.That(s.IsOpen, Is.False); Assert.That(interceptor.afterTransactionCompletionCalled, Is.EqualTo(1)); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/AdoNet/AbstractBatcher.cs b/src/NHibernate/AdoNet/AbstractBatcher.cs index f8b1b9662bb..33296d1546f 100644 --- a/src/NHibernate/AdoNet/AbstractBatcher.cs +++ b/src/NHibernate/AdoNet/AbstractBatcher.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Data.Common; using System.Diagnostics; using System.Threading; @@ -358,8 +359,11 @@ public void CloseReader(IDataReader reader) var actualReader = rsw == null ? reader : rsw.Target; _readersToClose.Remove(actualReader); + var duration = GetReaderStopwatch(actualReader); + try { + //TODO: Shouldn't we close reader instead? reader.Dispose(); } catch (Exception e) @@ -369,17 +373,24 @@ public void CloseReader(IDataReader reader) } LogCloseReader(); + LogDuration(duration); + } - if (!Log.IsDebugEnabled) - return; - - var nhReader = actualReader as NHybridDataReader; - actualReader = nhReader == null ? actualReader : nhReader.Target; + private Stopwatch GetReaderStopwatch(IDataReader reader) + { + var nhReader = reader as NHybridDataReader; + var actualReader = nhReader == null ? reader : nhReader.Target; Stopwatch duration; - if (_readersDuration.TryGetValue(actualReader, out duration) == false) - return; - _readersDuration.Remove(actualReader); + if (_readersDuration.TryGetValue(actualReader, out duration)) + _readersDuration.Remove(actualReader); + return duration; + } + + private static void LogDuration(Stopwatch duration) + { + if (!Log.IsDebugEnabled || duration == null) return; + Log.DebugFormat("DataReader was closed after {0} ms", duration.ElapsedMilliseconds); } diff --git a/src/NHibernate/Dialect/Dialect.cs b/src/NHibernate/Dialect/Dialect.cs index c9240005f95..1e2886ed1b2 100644 --- a/src/NHibernate/Dialect/Dialect.cs +++ b/src/NHibernate/Dialect/Dialect.cs @@ -2238,7 +2238,7 @@ public virtual bool IsKnownToken(string currentToken, string nextToken) protected void RegisterKeyword(string word) { - Keywords.Add(word); + _sqlKeywords.Add(word); } protected void RegisterFunction(string name, ISQLFunction function) diff --git a/src/NHibernate/Id/TableGenerator.cs b/src/NHibernate/Id/TableGenerator.cs index b4dea86eccc..5953cb75da9 100644 --- a/src/NHibernate/Id/TableGenerator.cs +++ b/src/NHibernate/Id/TableGenerator.cs @@ -220,67 +220,59 @@ public override object DoWorkInCurrentTransaction(ISessionImplementor session, I //select + uspdate even for no transaction //or read committed isolation level (needed for .net?) - IDbCommand qps = conn.CreateCommand(); - IDataReader rs = null; - qps.CommandText = query; - qps.CommandType = CommandType.Text; - qps.Transaction = transaction; - PersistentIdGeneratorParmsNames.SqlStatementLogger.LogCommand("Reading high value:", qps, FormatStyle.Basic); - try + using (var qps = conn.CreateCommand()) { - rs = qps.ExecuteReader(); - if (!rs.Read()) + qps.CommandText = query; + qps.CommandType = CommandType.Text; + qps.Transaction = transaction; + PersistentIdGeneratorParmsNames.SqlStatementLogger.LogCommand("Reading high value:", qps, FormatStyle.Basic); + try { - string err; - if (string.IsNullOrEmpty(whereClause)) + using (var rs = qps.ExecuteReader()) { - err = "could not read a hi value - you need to populate the table: " + tableName; + if (!rs.Read()) + { + string err; + if (string.IsNullOrEmpty(whereClause)) + { + err = "could not read a hi value - you need to populate the table: " + tableName; + } + else + { + err = string.Format("could not read a hi value from table '{0}' using the where clause ({1})- you need to populate the table.", tableName, whereClause); + } + log.Error(err); + throw new IdentifierGenerationException(err); + } + result = Convert.ToInt64(columnType.Get(rs, 0)); } - else - { - err = string.Format("could not read a hi value from table '{0}' using the where clause ({1})- you need to populate the table.", tableName, whereClause); - } - log.Error(err); - throw new IdentifierGenerationException(err); } - result = Convert.ToInt64(columnType.Get(rs, 0)); - } - catch (Exception e) - { - log.Error("could not read a hi value", e); - throw; - } - finally - { - if (rs != null) + catch (Exception e) { - rs.Close(); + log.Error("could not read a hi value", e); + throw; } - qps.Dispose(); } - IDbCommand ups = session.Factory.ConnectionProvider.Driver.GenerateCommand(CommandType.Text, updateSql, - parameterTypes); - ups.Connection = conn; - ups.Transaction = transaction; - - try + using (var ups = session.Factory.ConnectionProvider.Driver.GenerateCommand(CommandType.Text, updateSql, parameterTypes)) { - columnType.Set(ups, result + 1, 0); - columnType.Set(ups, result, 1); + ups.Connection = conn; + ups.Transaction = transaction; + + try + { + columnType.Set(ups, result + 1, 0); + columnType.Set(ups, result, 1); - PersistentIdGeneratorParmsNames.SqlStatementLogger.LogCommand("Updating high value:", ups, FormatStyle.Basic); + PersistentIdGeneratorParmsNames.SqlStatementLogger.LogCommand("Updating high value:", ups, FormatStyle.Basic); - rows = ups.ExecuteNonQuery(); - } - catch (Exception e) - { - log.Error("could not update hi value in: " + tableName, e); - throw; - } - finally - { - ups.Dispose(); + rows = ups.ExecuteNonQuery(); + } + catch (Exception e) + { + log.Error("could not update hi value in: " + tableName, e); + throw; + } } } while (rows == 0); diff --git a/src/NHibernate/Impl/AbstractSessionImpl.cs b/src/NHibernate/Impl/AbstractSessionImpl.cs index 85c3521afff..6558aa0ad09 100644 --- a/src/NHibernate/Impl/AbstractSessionImpl.cs +++ b/src/NHibernate/Impl/AbstractSessionImpl.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Data; +using System.Runtime.CompilerServices; using NHibernate.AdoNet; using NHibernate.Cache; using NHibernate.Collection; @@ -33,13 +34,14 @@ public abstract class AbstractSessionImpl : ISessionImplementor public ITransactionContext TransactionContext { - get; set; + [MethodImpl(MethodImplOptions.Synchronized)] + get; + [MethodImpl(MethodImplOptions.Synchronized)] + set; } private bool isAlreadyDisposed; - private static readonly IInternalLogger logger = LoggerProvider.LoggerFor(typeof(AbstractSessionImpl)); - public Guid SessionId { get { return sessionId; } @@ -330,6 +332,7 @@ protected internal void SetClosed() { if (TransactionContext != null) TransactionContext.Dispose(); + TransactionContext = null; } catch (Exception) { diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs index 7f19b79acac..6213879118d 100644 --- a/src/NHibernate/Impl/SessionImpl.cs +++ b/src/NHibernate/Impl/SessionImpl.cs @@ -1649,7 +1649,7 @@ public void Dispose() using (new SessionIdLoggingContext(SessionId)) { log.Debug(string.Format("[session-id={0}] running ISession.Dispose()", SessionId)); - if (TransactionContext != null) + if (Factory.TransactionFactory.IsInDistributedActiveTransaction(this)) { TransactionContext.ShouldCloseSessionOnDistributedTransactionCompleted = true; return; diff --git a/src/NHibernate/Impl/StatelessSessionImpl.cs b/src/NHibernate/Impl/StatelessSessionImpl.cs index 0e648b1997b..507694b7c37 100644 --- a/src/NHibernate/Impl/StatelessSessionImpl.cs +++ b/src/NHibernate/Impl/StatelessSessionImpl.cs @@ -862,7 +862,7 @@ public void Dispose() using (new SessionIdLoggingContext(SessionId)) { log.Debug("running IStatelessSession.Dispose()"); - if (TransactionContext != null) + if (Factory.TransactionFactory.IsInDistributedActiveTransaction(this)) { TransactionContext.ShouldCloseSessionOnDistributedTransactionCompleted = true; return; diff --git a/src/NHibernate/Transaction/AdoNetTransactionFactory.cs b/src/NHibernate/Transaction/AdoNetTransactionFactory.cs index ea9d993456c..29b22c50fe6 100644 --- a/src/NHibernate/Transaction/AdoNetTransactionFactory.cs +++ b/src/NHibernate/Transaction/AdoNetTransactionFactory.cs @@ -43,7 +43,7 @@ public void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork wo connection = session.Connection; else connection = session.Factory.ConnectionProvider.GetConnection(); - + if (transacted) { trans = connection.BeginTransaction(); @@ -117,4 +117,4 @@ public void Configure(IDictionary props) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs b/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs index 2290996dd6c..5698ec0325a 100644 --- a/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs +++ b/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Threading; using System.Transactions; using NHibernate.Engine; using NHibernate.Engine.Transaction; @@ -26,57 +27,26 @@ public void EnlistInDistributedTransactionIfNeeded(ISessionImplementor session) { if (session.TransactionContext != null) return; - - if (System.Transactions.Transaction.Current == null) + + var transaction = System.Transactions.Transaction.Current; + if (transaction == null) return; - - var transactionContext = new DistributedTransactionContext(session, - System.Transactions.Transaction.Current); - session.TransactionContext = transactionContext; - logger.DebugFormat("enlisted into DTC transaction: {0}", - transactionContext.AmbientTransation.IsolationLevel); - session.AfterTransactionBegin(null); - TransactionCompletedEventHandler handler = null; + var notification = new PrepareTransactionNotification(session, transaction); - handler = delegate(object sender, TransactionEventArgs e) - { - using (new SessionIdLoggingContext(session.SessionId)) - { - ((DistributedTransactionContext) session.TransactionContext).IsInActiveTransaction = false; + transaction.EnlistVolatile( + notification, + EnlistmentOptions.EnlistDuringPrepareRequired); - bool wasSuccessful = false; - try - { - wasSuccessful = e.Transaction.TransactionInformation.Status - == TransactionStatus.Committed; - } - catch (ObjectDisposedException ode) - { - logger.Warn("Completed transaction was disposed, assuming transaction rollback", ode); - } - session.AfterTransactionCompletion(wasSuccessful, null); - if (transactionContext.ShouldCloseSessionOnDistributedTransactionCompleted) - { - session.CloseSessionFromDistributedTransaction(); - } - session.TransactionContext = null; - } + session.TransactionContext = notification; - e.Transaction.TransactionCompleted -= handler; - }; - - transactionContext.AmbientTransation.TransactionCompleted += handler; - - transactionContext.AmbientTransation.EnlistVolatile(transactionContext, - EnlistmentOptions.EnlistDuringPrepareRequired); + logger.DebugFormat("enlisted into DTC transaction: {0}", transaction.IsolationLevel.ToString()); + session.AfterTransactionBegin(null); } public bool IsInDistributedActiveTransaction(ISessionImplementor session) { - var distributedTransactionContext = ((DistributedTransactionContext)session.TransactionContext); - return distributedTransactionContext != null && - distributedTransactionContext.IsInActiveTransaction; + return session.TransactionContext != null; } public void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, bool transacted) @@ -90,37 +60,38 @@ public void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork wo } } - public class DistributedTransactionContext : ITransactionContext, IEnlistmentNotification + class PrepareTransactionNotification : IEnlistmentNotification, ITransactionContext { - public System.Transactions.Transaction AmbientTransation { get; set; } - public bool ShouldCloseSessionOnDistributedTransactionCompleted { get; set; } - private readonly ISessionImplementor sessionImplementor; - public bool IsInActiveTransaction; + System.Transactions.Transaction _transaction; + + ISessionImplementor _session; - public DistributedTransactionContext(ISessionImplementor sessionImplementor, System.Transactions.Transaction transaction) + public PrepareTransactionNotification(ISessionImplementor session, System.Transactions.Transaction transaction) { - this.sessionImplementor = sessionImplementor; - AmbientTransation = transaction.Clone(); - IsInActiveTransaction = true; + _session = session; + _transaction = transaction.Clone(); } - #region IEnlistmentNotification Members + public bool ShouldCloseSessionOnDistributedTransactionCompleted { get; set; } void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment) { - using (new SessionIdLoggingContext(sessionImplementor.SessionId)) + using (new SessionIdLoggingContext(_session.SessionId)) { try { - using (var tx = new TransactionScope(AmbientTransation)) + using (var tx = new TransactionScope(_transaction)) { - sessionImplementor.BeforeTransactionCompletion(null); - if (sessionImplementor.FlushMode != FlushMode.Never && sessionImplementor.ConnectionManager.IsConnected) + _session.BeforeTransactionCompletion(null); + if (_session.FlushMode != FlushMode.Never && _session.ConnectionManager.IsConnected) { - using (sessionImplementor.ConnectionManager.FlushingFromDtcTransaction) + using (_session.ConnectionManager.FlushingFromDtcTransaction) { - logger.Debug(string.Format("[session-id={0}] Flushing from Dtc Transaction", sessionImplementor.SessionId)); - sessionImplementor.Flush(); + logger.Debug( + string.Format( + "[session-id={0}] Flushing from Dtc Transaction", + _session.SessionId.ToString())); + _session.Flush(); } } logger.Debug("prepared for DTC transaction"); @@ -131,7 +102,6 @@ void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment) } catch (Exception exception) { - logger.Error("DTC transaction prepare phase failed", exception); preparingEnlistment.ForceRollback(exception); } } @@ -139,45 +109,84 @@ void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment) void IEnlistmentNotification.Commit(Enlistment enlistment) { - using (new SessionIdLoggingContext(sessionImplementor.SessionId)) + using (this) + using (new SessionIdLoggingContext(_session.SessionId)) { - logger.Debug("committing DTC transaction"); - // we have nothing to do here, since it is the actual - // DB connection that will commit the transaction - enlistment.Done(); - IsInActiveTransaction = false; + try + { + logger.Debug("Committing DTC transaction"); + OnTransactionCompleted(true); + } + catch (Exception e) + { + logger.Warn("Exception happened at DTC transaction commit phase", e); + } + finally + { + enlistment.Done(); + } } } void IEnlistmentNotification.Rollback(Enlistment enlistment) { - using (new SessionIdLoggingContext(sessionImplementor.SessionId)) + using (this) + using (new SessionIdLoggingContext(_session.SessionId)) { - logger.Debug("rolled back DTC transaction"); - // Currently AfterTransactionCompletion is called by the handler for the TransactionCompleted event. - //sessionImplementor.AfterTransactionCompletion(false, null); - enlistment.Done(); - IsInActiveTransaction = false; + try + { + logger.Debug("Rolled back DTC transaction"); + OnTransactionCompleted(false); + } + catch (Exception e) + { + logger.Warn("Exception happened at DTC transaction rollback phase", e); + } + finally + { + enlistment.Done(); + } } } void IEnlistmentNotification.InDoubt(Enlistment enlistment) { - using (new SessionIdLoggingContext(sessionImplementor.SessionId)) + using (this) + using (new SessionIdLoggingContext(_session.SessionId)) { - sessionImplementor.AfterTransactionCompletion(false, null); - logger.Debug("DTC transaction is in doubt"); - enlistment.Done(); - IsInActiveTransaction = false; + try + { + logger.Debug("DTC transaction is in doubt"); + OnTransactionCompleted(false); + } + catch (Exception e) + { + logger.Warn("Exception happened at DTC transaction in doubt phase", e); + } + finally + { + enlistment.Done(); + } } } - #endregion - public void Dispose() { - if (AmbientTransation != null) - AmbientTransation.Dispose(); + if (!ReferenceEquals(_transaction, null)) + _transaction.Dispose(); + _transaction = null; + if (!ReferenceEquals(_session, null)) + _session.TransactionContext = null; + _session = null; + } + + void OnTransactionCompleted(bool successful) + { + var transactionContext = _session.TransactionContext; + _session.TransactionContext = null; + _session.AfterTransactionCompletion(successful, null); + if (transactionContext.ShouldCloseSessionOnDistributedTransactionCompleted) + _session.CloseSessionFromDistributedTransaction(); } } } diff --git a/src/NHibernate/Transaction/AdoTransaction.cs b/src/NHibernate/Transaction/AdoTransaction.cs index 9c18905b580..5ae9de41a2d 100644 --- a/src/NHibernate/Transaction/AdoTransaction.cs +++ b/src/NHibernate/Transaction/AdoTransaction.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Data; - +using System.Data.Common; using NHibernate.Engine; using NHibernate.Impl; @@ -55,11 +55,11 @@ public void Enlist(IDbCommand command) if (command.Transaction != null) { log.Warn("set a nonnull IDbCommand.Transaction to null because the Session had no Transaction"); + //throw new NotSupportedException("ORACLE!!!1111"); } } command.Transaction = null; - return; } else {