diff --git a/src/NHibernate.Test/DebugSessionFactory.cs b/src/NHibernate.Test/DebugSessionFactory.cs
index dfb6e5ce571..801b8f3a76e 100644
--- a/src/NHibernate.Test/DebugSessionFactory.cs
+++ b/src/NHibernate.Test/DebugSessionFactory.cs
@@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.Common;
+using System.Linq;
using System.Threading;
using log4net;
using NHibernate.Cache;
@@ -53,29 +54,41 @@ public bool CheckSessionsWereClosed()
var allClosed = true;
foreach (var session in _openedSessions)
{
- if (session.IsOpen)
+ // Do not inverse, we want to close all of them.
+ allClosed = CheckSessionWasClosed(session) && allClosed;
+ // Catches only session opened from another one while sharing the connection. Those
+ // opened without sharing the connection stay un-monitored.
+ foreach (var dependentSession in session.ConnectionManager.DependentSessions.ToList())
{
- if (session.TransactionContext?.ShouldCloseSessionOnDistributedTransactionCompleted ?? false)
- {
- // Delayed transactions not having completed and closed their sessions? Give them a chance to complete.
- Thread.Sleep(100);
- if (!session.IsOpen)
- {
- _log.Warn($"Test case had a delayed close of session {session.SessionId}.");
- continue;
- }
- }
-
- _log.Error($"Test case didn't close session {session.SessionId}, closing");
- allClosed = false;
- (session as ISession)?.Close();
- (session as IStatelessSession)?.Close();
+ allClosed = CheckSessionWasClosed(dependentSession) && allClosed;
}
}
return allClosed;
}
+ private bool CheckSessionWasClosed(ISessionImplementor session)
+ {
+ if (!session.IsOpen)
+ return true;
+
+ if (session.TransactionContext?.ShouldCloseSessionOnDistributedTransactionCompleted ?? false)
+ {
+ // Delayed transactions not having completed and closed their sessions? Give them a chance to complete.
+ Thread.Sleep(100);
+ if (!session.IsOpen)
+ {
+ _log.Warn($"Test case had a delayed close of session {session.SessionId}.");
+ return true;
+ }
+ }
+
+ _log.Error($"Test case didn't close session {session.SessionId}, closing");
+ (session as ISession)?.Close();
+ (session as IStatelessSession)?.Close();
+ return false;
+ }
+
ISessionBuilder ISessionFactory.WithOptions()
{
return new SessionBuilder(ActualFactory.WithOptions(), this);
diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj
index d8c04e36a8a..198851b6e86 100644
--- a/src/NHibernate.Test/NHibernate.Test.csproj
+++ b/src/NHibernate.Test/NHibernate.Test.csproj
@@ -1464,6 +1464,8 @@
+
+
@@ -3286,6 +3288,7 @@
+
diff --git a/src/NHibernate.Test/SystemTransactions/TransactionFixture.cs b/src/NHibernate.Test/SystemTransactions/TransactionFixture.cs
index cad02f86e90..de5dd5eb7c6 100644
--- a/src/NHibernate.Test/SystemTransactions/TransactionFixture.cs
+++ b/src/NHibernate.Test/SystemTransactions/TransactionFixture.cs
@@ -1,26 +1,23 @@
-using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
using System.Transactions;
-using NHibernate.DomainModel;
+using NHibernate.Linq;
+using NHibernate.Test.TransactionTest;
using NUnit.Framework;
namespace NHibernate.Test.SystemTransactions
{
[TestFixture]
- public class TransactionFixture : TestCase
+ public class TransactionFixture : TransactionFixtureBase
{
- protected override IList Mappings
- {
- get { return new string[] { "WZ.hbm.xml" }; }
- }
-
[Test]
public void CanUseSystemTransactionsToCommit()
{
- object identifier;
+ int identifier;
using(ISession session = Sfi.OpenSession())
using(TransactionScope tx = new TransactionScope())
{
- W s = new W();
+ var s = new Person();
session.Save(s);
identifier = s.Id;
tx.Complete();
@@ -29,11 +26,84 @@ public void CanUseSystemTransactionsToCommit()
using (ISession session = Sfi.OpenSession())
using (TransactionScope tx = new TransactionScope())
{
- W w = session.Get(identifier);
+ var w = session.Get(identifier);
Assert.IsNotNull(w);
session.Delete(w);
tx.Complete();
}
}
+
+ [Test]
+ public void FlushFromTransactionAppliesToDisposedSharingSession()
+ {
+ var flushOrder = new List();
+ using (var s = OpenSession(new TestInterceptor(0, flushOrder)))
+ {
+ var builder = s.SessionWithOptions().Connection();
+
+ using (var t = new TransactionScope())
+ {
+ var p1 = new Person();
+ var p2 = new Person();
+ var p3 = new Person();
+ var p4 = new Person();
+
+ using (var s1 = builder.Interceptor(new TestInterceptor(1, flushOrder)).OpenSession())
+ s1.Save(p1);
+ using (var s2 = builder.Interceptor(new TestInterceptor(2, flushOrder)).OpenSession())
+ {
+ s2.Save(p2);
+ using (var s3 = s2.SessionWithOptions().Connection().Interceptor(new TestInterceptor(3, flushOrder)).OpenSession())
+ s3.Save(p3);
+ }
+ s.Save(p4);
+ t.Complete();
+ }
+ }
+
+ Assert.That(flushOrder, Is.EqualTo(new[] { 0, 1, 2, 3 }));
+
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ Assert.That(s.Query().Count(), Is.EqualTo(4));
+ t.Commit();
+ }
+ }
+
+ [Test]
+ public void FlushFromTransactionAppliesToSharingSession()
+ {
+ var flushOrder = new List();
+ using (var s = OpenSession(new TestInterceptor(0, flushOrder)))
+ {
+ var builder = s.SessionWithOptions().Connection();
+
+ using (var s1 = builder.Interceptor(new TestInterceptor(1, flushOrder)).OpenSession())
+ using (var s2 = builder.Interceptor(new TestInterceptor(2, flushOrder)).OpenSession())
+ using (var s3 = s2.SessionWithOptions().Connection().Interceptor(new TestInterceptor(3, flushOrder)).OpenSession())
+ using (var t = new TransactionScope())
+ {
+ var p1 = new Person();
+ var p2 = new Person();
+ var p3 = new Person();
+ var p4 = new Person();
+ s1.Save(p1);
+ s2.Save(p2);
+ s3.Save(p3);
+ s.Save(p4);
+ t.Complete();
+ }
+ }
+
+ Assert.That(flushOrder, Is.EqualTo(new[] { 0, 1, 2, 3 }));
+
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ Assert.That(s.Query().Count(), Is.EqualTo(4));
+ t.Commit();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/NHibernate.Test/TransactionTest/Person.cs b/src/NHibernate.Test/TransactionTest/Person.cs
new file mode 100644
index 00000000000..39ad3f19626
--- /dev/null
+++ b/src/NHibernate.Test/TransactionTest/Person.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace NHibernate.Test.TransactionTest
+{
+ public class Person
+ {
+ public virtual int Id { get; set; }
+
+ public virtual DateTime CreatedAt { get; set; } = DateTime.Now;
+ }
+}
\ No newline at end of file
diff --git a/src/NHibernate.Test/TransactionTest/Person.hbm.xml b/src/NHibernate.Test/TransactionTest/Person.hbm.xml
new file mode 100644
index 00000000000..49c9ffc20e1
--- /dev/null
+++ b/src/NHibernate.Test/TransactionTest/Person.hbm.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NHibernate.Test/TransactionTest/TransactionFixture.cs b/src/NHibernate.Test/TransactionTest/TransactionFixture.cs
index 52b7a619c11..3c3d2e54a09 100644
--- a/src/NHibernate.Test/TransactionTest/TransactionFixture.cs
+++ b/src/NHibernate.Test/TransactionTest/TransactionFixture.cs
@@ -1,19 +1,15 @@
using System;
using System.Collections;
-using System.Data.Common;
+using System.Collections.Generic;
+using System.Linq;
+using NHibernate.Linq;
using NUnit.Framework;
namespace NHibernate.Test.TransactionTest
{
[TestFixture]
- public class TransactionFixture : TestCase
+ public class TransactionFixture : TransactionFixtureBase
{
- protected override IList Mappings
- {
- // The mapping is only actually needed in one test
- get { return new string[] {"Simple.hbm.xml"}; }
- }
-
[Test]
public void SecondTransactionShouldntBeCommitted()
{
@@ -74,25 +70,25 @@ public void CommandAfterTransactionShouldWork()
{
using (ISession s = OpenSession())
{
- using (ITransaction t = s.BeginTransaction())
+ using (s.BeginTransaction())
{
}
- s.CreateQuery("from Simple").List();
+ s.CreateQuery("from Person").List();
using (ITransaction t = s.BeginTransaction())
{
t.Commit();
}
- s.CreateQuery("from Simple").List();
+ s.CreateQuery("from Person").List();
using (ITransaction t = s.BeginTransaction())
{
t.Rollback();
}
- s.CreateQuery("from Simple").List();
+ s.CreateQuery("from Person").List();
}
}
@@ -141,5 +137,40 @@ public void WasCommittedOrRolledBack()
}
}
}
+
+ [Test]
+ public void FlushFromTransactionAppliesToSharingSession()
+ {
+ var flushOrder = new List();
+ using (var s = OpenSession(new TestInterceptor(0, flushOrder)))
+ {
+ var builder = s.SessionWithOptions().Connection();
+
+ using (var s1 = builder.Interceptor(new TestInterceptor(1, flushOrder)).OpenSession())
+ using (var s2 = builder.Interceptor(new TestInterceptor(2, flushOrder)).OpenSession())
+ using (var s3 = s1.SessionWithOptions().Connection().Interceptor(new TestInterceptor(3, flushOrder)).OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ var p1 = new Person();
+ var p2 = new Person();
+ var p3 = new Person();
+ var p4 = new Person();
+ s1.Save(p1);
+ s2.Save(p2);
+ s3.Save(p3);
+ s.Save(p4);
+ t.Commit();
+ }
+ }
+
+ Assert.That(flushOrder, Is.EqualTo(new[] { 0, 1, 2, 3 }));
+
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ Assert.That(s.Query().Count(), Is.EqualTo(4));
+ t.Commit();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/NHibernate.Test/TransactionTest/TransactionFixtureBase.cs b/src/NHibernate.Test/TransactionTest/TransactionFixtureBase.cs
new file mode 100644
index 00000000000..2ad374951cd
--- /dev/null
+++ b/src/NHibernate.Test/TransactionTest/TransactionFixtureBase.cs
@@ -0,0 +1,39 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace NHibernate.Test.TransactionTest
+{
+ public abstract class TransactionFixtureBase : TestCase
+ {
+ protected override IList Mappings => new[] { "TransactionTest.Person.hbm.xml" };
+
+ protected override string MappingsAssembly => "NHibernate.Test";
+
+ protected override void OnTearDown()
+ {
+ using (var s = OpenSession())
+ using (var t = s.BeginTransaction())
+ {
+ s.Delete("from System.Object");
+ t.Commit();
+ }
+ }
+
+ public class TestInterceptor : EmptyInterceptor
+ {
+ private readonly int _numero;
+ private readonly List _flushOrder;
+
+ public TestInterceptor(int numero, List flushOrder)
+ {
+ _numero = numero;
+ _flushOrder = flushOrder;
+ }
+
+ public override void PreFlush(ICollection entitites)
+ {
+ _flushOrder.Add(_numero);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NHibernate/AdoNet/ConnectionManager.cs b/src/NHibernate/AdoNet/ConnectionManager.cs
index 78274014e0f..258fc4aa7fe 100644
--- a/src/NHibernate/AdoNet/ConnectionManager.cs
+++ b/src/NHibernate/AdoNet/ConnectionManager.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Runtime.Serialization;
@@ -41,6 +42,17 @@ public interface Callback
private readonly ISessionImplementor session;
private readonly ConnectionReleaseMode connectionReleaseMode;
private readonly IInterceptor interceptor;
+ private readonly List _dependentSessions = new List();
+
+ ///
+ /// The session responsible for the lifecycle of the connection manager.
+ ///
+ public ISessionImplementor Session => session;
+
+ ///
+ /// The sessions using the connection manager of the session responsible for it.
+ ///
+ public IReadOnlyCollection DependentSessions => _dependentSessions;
[NonSerialized]
private bool _releasesEnabled = true;
@@ -63,6 +75,16 @@ public ConnectionManager(
ownConnection = suppliedConnection == null;
}
+ public void AddDependentSession(ISessionImplementor session)
+ {
+ _dependentSessions.Add(session);
+ }
+
+ public void RemoveDependentSession(ISessionImplementor session)
+ {
+ _dependentSessions.Remove(session);
+ }
+
public bool IsInActiveTransaction
{
get
diff --git a/src/NHibernate/Engine/ISessionImplementor.cs b/src/NHibernate/Engine/ISessionImplementor.cs
index e93c9082035..c59be757f01 100644
--- a/src/NHibernate/Engine/ISessionImplementor.cs
+++ b/src/NHibernate/Engine/ISessionImplementor.cs
@@ -186,6 +186,11 @@ public interface ISessionImplementor
///
void BeforeTransactionCompletion(ITransaction tx);
+ ///
+ ///
+ ///
+ void FlushBeforeTransactionCompletion();
+
///
/// Notify the session that the transaction completed, so we no longer own the old locks.
/// (Also we should release cache softlocks). May be called multiple times during the transaction
diff --git a/src/NHibernate/ISharedSessionBuilder.cs b/src/NHibernate/ISharedSessionBuilder.cs
index 9bbbddbc6cd..964cf9464a7 100644
--- a/src/NHibernate/ISharedSessionBuilder.cs
+++ b/src/NHibernate/ISharedSessionBuilder.cs
@@ -9,6 +9,8 @@ public interface ISharedSessionBuilder : ISessionBuilder
{
///
/// Signifies that the connection from the original session should be used to create the new session.
+ /// The original session remains responsible for it and its closing will cause sharing sessions to be no
+ /// more usable.
///
/// , for method chaining.
ISharedSessionBuilder Connection();
diff --git a/src/NHibernate/Impl/AbstractSessionImpl.cs b/src/NHibernate/Impl/AbstractSessionImpl.cs
index 9c6e844fa62..cc1363f461c 100644
--- a/src/NHibernate/Impl/AbstractSessionImpl.cs
+++ b/src/NHibernate/Impl/AbstractSessionImpl.cs
@@ -152,6 +152,7 @@ public virtual IList List(CriteriaImpl criteria)
public abstract IEntityPersister GetEntityPersister(string entityName, object obj);
public abstract void AfterTransactionBegin(ITransaction tx);
public abstract void BeforeTransactionCompletion(ITransaction tx);
+ public abstract void FlushBeforeTransactionCompletion();
public abstract void AfterTransactionCompletion(bool successful, ITransaction tx);
public abstract object GetContextEntityIdentifier(object obj);
public abstract object Instantiate(string clazz, object id);
@@ -430,6 +431,7 @@ protected void AfterOperation(bool success)
if (!ConnectionManager.IsInActiveTransaction)
{
ConnectionManager.AfterNonTransactionalQuery(success);
+ ConnectionManager.AfterTransaction();
AfterTransactionCompletion(success, null);
}
}
diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs
index bc0704ceebc..a6e86c5d984 100644
--- a/src/NHibernate/Impl/SessionImpl.cs
+++ b/src/NHibernate/Impl/SessionImpl.cs
@@ -201,6 +201,7 @@ internal SessionImpl(SessionFactoryImpl factory, ISessionCreationOptions options
if (options.UserSuppliedConnection != null)
throw new SessionException("Cannot simultaneously share transaction context and specify connection");
connectionManager = sharedOptions.ConnectionManager;
+ connectionManager.AddDependentSession(this);
}
else
{
@@ -298,8 +299,8 @@ public DbConnection Close()
{
if (!_transactionCoordinatorShared)
return connectionManager.Close();
- else
- return null;
+ connectionManager.RemoveDependentSession(this);
+ return null;
}
finally
{
@@ -319,26 +320,23 @@ public override void AfterTransactionCompletion(bool success, ITransaction tx)
using (new SessionIdLoggingContext(SessionId))
{
log.Debug("transaction completion");
+
+ persistenceContext.AfterTransactionCompletion();
+ actionQueue.AfterTransactionCompletion(success);
+
if (Factory.Statistics.IsStatisticsEnabled)
{
Factory.StatisticsImplementor.EndTransaction(success);
}
- connectionManager.AfterTransaction();
- persistenceContext.AfterTransactionCompletion();
- actionQueue.AfterTransactionCompletion(success);
- if (!_transactionCoordinatorShared)
+ try
{
- try
- {
- Interceptor.AfterTransactionCompletion(tx);
- }
- catch (Exception t)
- {
- log.Error("exception in interceptor afterTransactionCompletion()", t);
- }
+ Interceptor.AfterTransactionCompletion(tx);
+ }
+ catch (Exception t)
+ {
+ log.Error("exception in interceptor afterTransactionCompletion()", t);
}
-
//if (autoClear)
// Clear();
@@ -2101,23 +2099,30 @@ public override void BeforeTransactionCompletion(ITransaction tx)
using (new SessionIdLoggingContext(SessionId))
{
log.Debug("before transaction completion");
+ FlushBeforeTransactionCompletion();
actionQueue.BeforeTransactionCompletion();
- if (!_transactionCoordinatorShared)
+ try
{
- try
- {
- Interceptor.BeforeTransactionCompletion(tx);
- }
- catch (Exception e)
- {
- log.Error("exception in interceptor BeforeTransactionCompletion()", e);
+ Interceptor.BeforeTransactionCompletion(tx);
+ }
+ catch (Exception e)
+ {
+ log.Error("exception in interceptor BeforeTransactionCompletion()", e);
- throw;
- }
+ throw;
}
}
}
+ public override void FlushBeforeTransactionCompletion()
+ {
+ using (new SessionIdLoggingContext(SessionId))
+ {
+ if (FlushMode != FlushMode.Manual)
+ Flush();
+ }
+ }
+
public ISession SetBatchSize(int batchSize)
{
Batcher.BatchSize = batchSize;
diff --git a/src/NHibernate/Impl/StatelessSessionImpl.cs b/src/NHibernate/Impl/StatelessSessionImpl.cs
index 6933c4e3a82..c0f5565ab74 100644
--- a/src/NHibernate/Impl/StatelessSessionImpl.cs
+++ b/src/NHibernate/Impl/StatelessSessionImpl.cs
@@ -27,8 +27,10 @@ namespace NHibernate.Impl
public class StatelessSessionImpl : AbstractSessionImpl, IStatelessSession
{
private static readonly IInternalLogger log = LoggerProvider.LoggerFor(typeof(StatelessSessionImpl));
+
[NonSerialized]
private readonly ConnectionManager connectionManager;
+
[NonSerialized]
private readonly StatefulPersistenceContext temporaryPersistenceContext;
@@ -179,7 +181,7 @@ public override void List(CriteriaImpl criteria, IList results)
temporaryPersistenceContext.Clear();
}
}
-
+
public override IEnumerable Enumerable(IQueryExpression queryExpression, QueryParameters queryParameters)
{
throw new NotImplementedException();
@@ -216,16 +218,22 @@ public override void AfterTransactionBegin(ITransaction tx)
public override void BeforeTransactionCompletion(ITransaction tx)
{
+ FlushBeforeTransactionCompletion();
}
- public override void AfterTransactionCompletion(bool successful, ITransaction tx)
+ public override void FlushBeforeTransactionCompletion()
{
using (new SessionIdLoggingContext(SessionId))
{
- connectionManager.AfterTransaction();
+ if (FlushMode != FlushMode.Manual)
+ Flush();
}
}
+ public override void AfterTransactionCompletion(bool successful, ITransaction tx)
+ {
+ }
+
public override object GetContextEntityIdentifier(object obj)
{
CheckAndUpdateSessionStatus();
@@ -838,6 +846,7 @@ public ITransaction BeginTransaction(IsolationLevel isolationLevel)
#endregion
#region IDisposable Members
+
private bool _isAlreadyDisposed;
///
diff --git a/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs b/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs
index d2cdceb3c2c..6b7fc7ab64b 100644
--- a/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs
+++ b/src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections;
+using System.Linq;
using System.Transactions;
using NHibernate.Engine;
using NHibernate.Engine.Transaction;
@@ -29,13 +30,26 @@ public void EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
if (System.Transactions.Transaction.Current == null)
return;
-
+
+ var originatingSession = session.ConnectionManager.Session;
+ if (originatingSession != session)
+ {
+ session.TransactionContext = new DependentContext();
+ }
+
+ if (originatingSession.TransactionContext != null)
+ return;
+
+ session = originatingSession;
+
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);
+ foreach (var dependentSession in session.ConnectionManager.DependentSessions)
+ dependentSession.AfterTransactionBegin(null);
TransactionCompletedEventHandler handler = null;
@@ -55,12 +69,12 @@ public void EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
{
logger.Warn("Completed transaction was disposed, assuming transaction rollback", ode);
}
+ session.ConnectionManager.AfterTransaction();
session.AfterTransactionCompletion(wasSuccessful, null);
- if (transactionContext.ShouldCloseSessionOnDistributedTransactionCompleted)
- {
- session.CloseSessionFromDistributedTransaction();
- }
- session.TransactionContext = null;
+ foreach (var dependentSession in session.ConnectionManager.DependentSessions)
+ dependentSession.AfterTransactionCompletion(wasSuccessful, null);
+
+ Cleanup(session);
}
e.Transaction.TransactionCompleted -= handler;
@@ -72,9 +86,27 @@ public void EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
EnlistmentOptions.EnlistDuringPrepareRequired);
}
+ private static void Cleanup(ISessionImplementor session)
+ {
+ foreach (var dependentSession in session.ConnectionManager.DependentSessions.ToList())
+ {
+ if (dependentSession.TransactionContext?.ShouldCloseSessionOnDistributedTransactionCompleted ?? false)
+ // This change the enumerated collection.
+ dependentSession.CloseSessionFromDistributedTransaction();
+ dependentSession.TransactionContext?.Dispose();
+ dependentSession.TransactionContext = null;
+ }
+ if (session.TransactionContext.ShouldCloseSessionOnDistributedTransactionCompleted)
+ {
+ session.CloseSessionFromDistributedTransaction();
+ }
+ session.TransactionContext.Dispose();
+ session.TransactionContext = null;
+ }
+
public bool IsInDistributedActiveTransaction(ISessionImplementor session)
{
- var distributedTransactionContext = ((DistributedTransactionContext)session.TransactionContext);
+ var distributedTransactionContext = (DistributedTransactionContext)session.ConnectionManager.Session.TransactionContext;
return distributedTransactionContext != null &&
distributedTransactionContext.IsInActiveTransaction;
}
@@ -114,18 +146,19 @@ void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
{
using (var tx = new TransactionScope(AmbientTransation))
{
- sessionImplementor.BeforeTransactionCompletion(null);
- if (sessionImplementor.FlushMode != FlushMode.Manual && sessionImplementor.ConnectionManager.IsConnected)
+ if (sessionImplementor.ConnectionManager.IsConnected)
{
using (sessionImplementor.ConnectionManager.FlushingFromDtcTransaction)
{
- logger.Debug(string.Format("[session-id={0}] Flushing from Dtc Transaction", sessionImplementor.SessionId));
- sessionImplementor.Flush();
+ sessionImplementor.BeforeTransactionCompletion(null);
+ foreach (var dependentSession in sessionImplementor.ConnectionManager.DependentSessions)
+ dependentSession.BeforeTransactionCompletion(null);
+
+ logger.Debug("prepared for DTC transaction");
+
+ tx.Complete();
}
}
- logger.Debug("prepared for DTC transaction");
-
- tx.Complete();
}
preparingEnlistment.Prepared();
}
@@ -165,7 +198,10 @@ void IEnlistmentNotification.InDoubt(Enlistment enlistment)
{
using (new SessionIdLoggingContext(sessionImplementor.SessionId))
{
+ sessionImplementor.ConnectionManager.AfterTransaction();
sessionImplementor.AfterTransactionCompletion(false, null);
+ foreach (var dependentSession in sessionImplementor.ConnectionManager.DependentSessions)
+ dependentSession.AfterTransactionCompletion(false, null);
logger.Debug("DTC transaction is in doubt");
enlistment.Done();
IsInActiveTransaction = false;
@@ -180,5 +216,12 @@ public void Dispose()
AmbientTransation.Dispose();
}
}
+
+ public class DependentContext : ITransactionContext
+ {
+ public bool ShouldCloseSessionOnDistributedTransactionCompleted { get; set; }
+
+ public void Dispose() { }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate/Transaction/AdoTransaction.cs b/src/NHibernate/Transaction/AdoTransaction.cs
index 162cba606e1..3b3f79ac5d6 100644
--- a/src/NHibernate/Transaction/AdoTransaction.cs
+++ b/src/NHibernate/Transaction/AdoTransaction.cs
@@ -154,6 +154,8 @@ public void Begin(IsolationLevel isolationLevel)
rolledBack = false;
session.AfterTransactionBegin(this);
+ foreach (var dependentSession in session.ConnectionManager.DependentSessions)
+ dependentSession.AfterTransactionBegin(this);
}
}
@@ -161,8 +163,12 @@ private void AfterTransactionCompletion(bool successful)
{
using (new SessionIdLoggingContext(sessionId))
{
+ session.ConnectionManager.AfterTransaction();
session.AfterTransactionCompletion(successful, this);
NotifyLocalSynchsAfterTransactionCompletion(successful);
+ foreach (var dependentSession in session.ConnectionManager.DependentSessions)
+ dependentSession.AfterTransactionCompletion(successful, this);
+
session = null;
begun = false;
}
@@ -186,13 +192,10 @@ public void Commit()
log.Debug("Start Commit");
- if (session.FlushMode != FlushMode.Manual)
- {
- session.Flush();
- }
-
- NotifyLocalSynchsBeforeTransactionCompletion();
session.BeforeTransactionCompletion(this);
+ NotifyLocalSynchsBeforeTransactionCompletion();
+ foreach (var dependentSession in session.ConnectionManager.DependentSessions)
+ dependentSession.BeforeTransactionCompletion(this);
try
{