diff --git a/src/NHibernate.Test/Linq/StatelessSessionQueringTest.cs b/src/NHibernate.Test/Linq/StatelessSessionQueringTest.cs index 9af288d9d2f..022aaef2305 100644 --- a/src/NHibernate.Test/Linq/StatelessSessionQueringTest.cs +++ b/src/NHibernate.Test/Linq/StatelessSessionQueringTest.cs @@ -8,6 +8,77 @@ namespace NHibernate.Test.Linq { public class StatelessSessionQueringTest : LinqTestCase { + [Test] + public void CanQueryChildStatelessSession() + { + //NH-3606 + using (var session = this.OpenSession()) + { + Assert.AreEqual(0, session.GetSessionImplementation().PersistenceContext.EntityEntries.Count); + + using (var statelessSession = session.GetStatelessSession()) + { + var results = statelessSession.Query().ToList(); + + Assert.IsNotEmpty(results); + } + + Assert.AreEqual(0, session.GetSessionImplementation().PersistenceContext.EntityEntries.Count); + } + } + + [Test] + public void CanCreateStatelessSessions() + { + //NH-3606 + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + Assert.IsTrue(session.Transaction.IsActive); + + using (var statelessSession = session.GetStatelessSession()) + { + Assert.IsTrue(statelessSession.Transaction.IsActive); + + statelessSession.Transaction.Rollback(); + } + + Assert.IsFalse(session.Transaction.IsActive); + } + } + + [Test] + public void CanApplyAsStatelessExtensionMethod() + { + //NH-3606 + using (var session = OpenSession()) + { + Assert.AreEqual(0, session.GetSessionImplementation().PersistenceContext.EntityEntries.Count); + + var results = session.Query().AsStateless().ToList(); + + Assert.IsNotEmpty(results); + + Assert.AreEqual(0, session.GetSessionImplementation().PersistenceContext.EntityEntries.Count); + } + } + + [Test] + public void ExplicitlyFetchedLazyMembersAreNotCached() + { + //NH-3606 + using (var session = OpenSession()) + { + Assert.AreEqual(0, session.GetSessionImplementation().PersistenceContext.EntityEntries.Count); + + var results = session.Query().AsStateless().Fetch(x => x.Orders).ToList(); + + Assert.IsNotEmpty(results); + + Assert.AreEqual(0, session.GetSessionImplementation().PersistenceContext.EntityEntries.Count); + } + } + [Test] public void WhenQueryThroughStatelessSessionThenDoesNotThrows() { diff --git a/src/NHibernate/AdoNet/ConnectionManager.cs b/src/NHibernate/AdoNet/ConnectionManager.cs index 5ace6b15a2f..6affc96c534 100644 --- a/src/NHibernate/AdoNet/ConnectionManager.cs +++ b/src/NHibernate/AdoNet/ConnectionManager.cs @@ -34,7 +34,7 @@ public interface Callback private bool ownConnection; [NonSerialized] - private ITransaction transaction; + internal ITransaction transaction; [NonSerialized] private IBatcher batcher; diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs index 27a127fd3e1..68e8705eb16 100644 --- a/src/NHibernate/Impl/SessionImpl.cs +++ b/src/NHibernate/Impl/SessionImpl.cs @@ -78,6 +78,10 @@ public sealed class SessionImpl : AbstractSessionImpl, IEventSource, ISerializab [NonSerialized] ISession _childSession; + //NH-3606 + [NonSerialized] + private IStatelessSession childStatelessSession; + [NonSerialized] private readonly bool flushBeforeCompletionEnabled; [NonSerialized] @@ -359,12 +363,20 @@ public DbConnection Close() { try { + //NH-3606 + if (childStatelessSession != null) + { + childStatelessSession.Close(); + childStatelessSession = null; + } + if (_childSession != null) { if (_childSession.IsOpen) { _childSession.Close(); } + _childSession = null; } } catch @@ -2210,6 +2222,27 @@ public ISessionImplementor GetSessionImplementation() return this; } + //NH-3606 + public IStatelessSession GetStatelessSession() + { + using (new SessionIdLoggingContext(SessionId)) + { + if (rootSession != null) + { + return rootSession.GetStatelessSession(); + } + + if (childStatelessSession == null) + { + childStatelessSession = new StatelessSessionImpl(Connection, SessionFactory as SessionFactoryImpl); + + (childStatelessSession as StatelessSessionImpl).ConnectionManager.transaction = Transaction; + } + + return childStatelessSession; + } + } + public ISession GetChildSession() { using (new SessionIdLoggingContext(SessionId)) diff --git a/src/NHibernate/Linq/DefaultQueryProvider.cs b/src/NHibernate/Linq/DefaultQueryProvider.cs index e2c9d09f441..b8e7a4ee534 100644 --- a/src/NHibernate/Linq/DefaultQueryProvider.cs +++ b/src/NHibernate/Linq/DefaultQueryProvider.cs @@ -28,7 +28,7 @@ public DefaultQueryProvider(ISessionImplementor session) _session = new WeakReference(session, true); } - protected virtual ISessionImplementor Session + protected internal virtual ISessionImplementor Session { get { return _session.Target as ISessionImplementor; } } diff --git a/src/NHibernate/Linq/LinqExtensionMethods.cs b/src/NHibernate/Linq/LinqExtensionMethods.cs index e783502aceb..b51be4d679d 100755 --- a/src/NHibernate/Linq/LinqExtensionMethods.cs +++ b/src/NHibernate/Linq/LinqExtensionMethods.cs @@ -13,6 +13,14 @@ namespace NHibernate.Linq { public static class LinqExtensionMethods { + public static IQueryable AsStateless(this IQueryable query) + { + var session = (query.Provider as DefaultQueryProvider).Session; + var statelessSession = (session as SessionImpl).GetStatelessSession(); + + return new DefaultQueryProvider(statelessSession.GetSessionImplementation()).CreateQuery(query.Expression); + } + public static IQueryable Query(this ISession session) { return new NhQueryable(session.GetSessionImplementation()); diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index c25e725fff8..46963701ab8 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -620,6 +620,7 @@ + diff --git a/src/NHibernate/SessionExtensions.cs b/src/NHibernate/SessionExtensions.cs new file mode 100644 index 00000000000..c662521b9e0 --- /dev/null +++ b/src/NHibernate/SessionExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NHibernate.Impl; + +namespace NHibernate +{ + public static class SessionExtensions + { + public static IStatelessSession GetStatelessSession(this ISession session) + { + return (session.GetSessionImplementation() as SessionImpl).GetStatelessSession(); + } + } +}