Skip to content

Commit dce4d02

Browse files
authoredMar 11, 2018
NH-3606 - open a stateless session from a session (#1520)
- Fixes #910
1 parent 058ecce commit dce4d02

18 files changed

+491
-230
lines changed
 

‎src/NHibernate.Test/Async/SessionBuilder/Fixture.cs

+61-7
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,28 @@ private void CanSetAutoJoinTransaction<T>(T sb) where T : ISessionBuilder<T>
5454
false, true);
5555
}
5656

57+
private void CanSetAutoJoinTransactionOnStateless<T>(T sb) where T : IStatelessSessionBuilder
58+
{
59+
var options = DebugSessionFactory.GetCreationOptions(sb);
60+
CanSetOnStateless(
61+
sb, sb.AutoJoinTransaction, () => options.ShouldAutoJoinTransaction,
62+
sb is ISharedStatelessSessionBuilder ssb ? ssb.AutoJoinTransaction : default(Func<ISharedStatelessSessionBuilder>),
63+
// initial value
64+
true,
65+
// values
66+
false, true);
67+
}
68+
5769
[Test]
5870
public async Task CanSetConnectionAsync()
5971
{
6072
var sb = Sfi.WithOptions();
6173
await (CanSetConnectionAsync(sb));
74+
await (CanSetConnectionOnStatelessAsync(Sfi.WithStatelessOptions()));
6275
using (var s = sb.OpenSession())
6376
{
6477
await (CanSetConnectionAsync(s.SessionWithOptions()));
78+
await (CanSetConnectionOnStatelessAsync(s.StatelessSessionWithOptions()));
6579
}
6680
}
6781

@@ -109,12 +123,10 @@ public async Task CanSetConnectionAsync()
109123
}
110124
}
111125

112-
[Test]
113-
public async Task CanSetConnectionOnStatelessAsync()
126+
private async Task CanSetConnectionOnStatelessAsync<T>(T sb, CancellationToken cancellationToken = default(CancellationToken)) where T : IStatelessSessionBuilder
114127
{
115-
var sb = Sfi.WithStatelessOptions();
116128
var sbType = sb.GetType().Name;
117-
var conn = await (Sfi.ConnectionProvider.GetConnectionAsync(CancellationToken.None));
129+
var conn = await (Sfi.ConnectionProvider.GetConnectionAsync(cancellationToken));
118130
try
119131
{
120132
var options = DebugSessionFactory.GetCreationOptions(sb);
@@ -123,9 +135,31 @@ public async Task CanSetConnectionOnStatelessAsync()
123135
Assert.AreEqual(conn, options.UserSuppliedConnection, $"{sbType}: After call with a connection");
124136
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with a connection");
125137

126-
fsb = sb.Connection(null);
127-
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with null");
128-
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with null");
138+
if (sb is ISharedStatelessSessionBuilder ssb)
139+
{
140+
var sharedOptions = (ISharedSessionCreationOptions)options;
141+
Assert.IsFalse(sharedOptions.IsTransactionCoordinatorShared, $"{sbType}: Transaction coordinator shared before sharing");
142+
Assert.IsNull(sharedOptions.ConnectionManager, $"{sbType}: Connection manager shared before sharing");
143+
144+
var fssb = ssb.Connection();
145+
// Sharing connection shares the connection manager, not the connection.
146+
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with previous session connection");
147+
Assert.IsTrue(sharedOptions.IsTransactionCoordinatorShared, $"{sbType}: Transaction coordinator not shared after sharing");
148+
Assert.IsNotNull(sharedOptions.ConnectionManager, $"{sbType}: Connection manager not shared after sharing");
149+
Assert.AreEqual(sb, fssb, $"{sbType}: Unexpected fluent return on shared");
150+
151+
fsb = sb.Connection(null);
152+
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with null");
153+
Assert.IsFalse(sharedOptions.IsTransactionCoordinatorShared, $"{sbType}: Transaction coordinator shared after un-sharing");
154+
Assert.IsNull(sharedOptions.ConnectionManager, $"{sbType}: Connection manager shared after un-sharing");
155+
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after un-sharing");
156+
}
157+
else
158+
{
159+
fsb = sb.Connection(null);
160+
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with null");
161+
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with null");
162+
}
129163
}
130164
finally
131165
{
@@ -218,5 +252,25 @@ private void CanSet<T, V>(T sb, Func<V, T> setter, Func<V> getter, Func<ISharedS
218252
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with {value}");
219253
}
220254
}
255+
256+
private void CanSetOnStateless<T, V>(
257+
T sb, Func<V, T> setter, Func<V> getter, Func<ISharedStatelessSessionBuilder> shared, V initialValue,
258+
params V[] values) where T : IStatelessSessionBuilder
259+
{
260+
var sbType = sb.GetType().Name;
261+
Assert.AreEqual(initialValue, getter(), $"{sbType}: Initial value");
262+
if (shared != null)
263+
{
264+
var fssb = shared();
265+
Assert.AreEqual(values.Last(), getter(), $"{sbType}: After call with shared setting");
266+
Assert.AreEqual(sb, fssb, $"{sbType}: Unexpected fluent return on shared");
267+
}
268+
foreach (var value in values)
269+
{
270+
var fsb = setter(value);
271+
Assert.AreEqual(value, getter(), $"{sbType}: After call with {value}");
272+
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with {value}");
273+
}
274+
}
221275
}
222276
}

‎src/NHibernate.Test/Async/TransactionTest/TransactionFixture.cs

+30-1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,35 @@ public async Task FlushFromTransactionAppliesToSharingSessionAsync()
170170
}
171171
}
172172

173+
[Test]
174+
public async Task FlushFromTransactionAppliesToSharingStatelessSessionAsync()
175+
{
176+
using (var s = OpenSession())
177+
{
178+
var builder = s.StatelessSessionWithOptions().Connection();
179+
180+
using (var s1 = builder.OpenStatelessSession())
181+
using (var s2 = builder.OpenStatelessSession())
182+
using (var t = s.BeginTransaction())
183+
{
184+
var p1 = new Person();
185+
var p2 = new Person();
186+
var p3 = new Person();
187+
await (s1.InsertAsync(p1));
188+
await (s2.InsertAsync(p2));
189+
await (s.SaveAsync(p3));
190+
await (t.CommitAsync());
191+
}
192+
}
193+
194+
using (var s = OpenSession())
195+
using (var t = s.BeginTransaction())
196+
{
197+
Assert.That(await (s.Query<Person>().CountAsync()), Is.EqualTo(3));
198+
await (t.CommitAsync());
199+
}
200+
}
201+
173202
// Taken and adjusted from NH1632 When_commiting_items_in_DTC_transaction_will_add_items_to_2nd_level_cache
174203
[Test]
175204
public async Task WhenCommittingItemsWillAddThemTo2ndLevelCacheAsync()
@@ -210,4 +239,4 @@ public async Task WhenCommittingItemsWillAddThemTo2ndLevelCacheAsync()
210239
}
211240
}
212241
}
213-
}
242+
}

‎src/NHibernate.Test/DebugSessionFactory.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ public static ISessionCreationOptions GetCreationOptions<T>(ISessionBuilder<T> s
386386

387387
public static ISessionCreationOptions GetCreationOptions(IStatelessSessionBuilder sessionBuilder)
388388
{
389-
return ((StatelessSessionBuilder)sessionBuilder).CreationOptions;
389+
return (sessionBuilder as StatelessSessionBuilder)?.CreationOptions ??
390+
(ISessionCreationOptions)sessionBuilder;
390391
}
391392

392393
internal class SessionBuilder : ISessionBuilder

‎src/NHibernate.Test/SessionBuilder/Fixture.cs

+58-19
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ public void CanSetAutoJoinTransaction()
4747
{
4848
var sb = Sfi.WithOptions();
4949
CanSetAutoJoinTransaction(sb);
50+
CanSetAutoJoinTransactionOnStateless(Sfi.WithStatelessOptions());
5051
using (var s = sb.OpenSession())
5152
{
5253
CanSetAutoJoinTransaction(s.SessionWithOptions());
54+
CanSetAutoJoinTransactionOnStateless(s.StatelessSessionWithOptions());
5355
}
5456
}
5557

@@ -64,31 +66,28 @@ private void CanSetAutoJoinTransaction<T>(T sb) where T : ISessionBuilder<T>
6466
false, true);
6567
}
6668

67-
[Test]
68-
public void CanSetAutoJoinTransactionOnStateless()
69+
private void CanSetAutoJoinTransactionOnStateless<T>(T sb) where T : IStatelessSessionBuilder
6970
{
70-
var sb = Sfi.WithStatelessOptions();
71-
72-
var sbType = sb.GetType().Name;
7371
var options = DebugSessionFactory.GetCreationOptions(sb);
74-
Assert.That(options.ShouldAutoJoinTransaction, Is.True, $"{sbType}: Initial value");
75-
var fsb = sb.AutoJoinTransaction(false);
76-
Assert.That(options.ShouldAutoJoinTransaction, Is.False, $"{sbType}: After call with false");
77-
Assert.That(fsb, Is.SameAs(sb), $"{sbType}: Unexpected fluent return after call with false");
78-
79-
fsb = sb.AutoJoinTransaction(true);
80-
Assert.That(options.ShouldAutoJoinTransaction, Is.True, $"{sbType}: After call with true");
81-
Assert.That(fsb, Is.SameAs(sb), $"{sbType}: Unexpected fluent return after call with true");
72+
CanSetOnStateless(
73+
sb, sb.AutoJoinTransaction, () => options.ShouldAutoJoinTransaction,
74+
sb is ISharedStatelessSessionBuilder ssb ? ssb.AutoJoinTransaction : default(Func<ISharedStatelessSessionBuilder>),
75+
// initial value
76+
true,
77+
// values
78+
false, true);
8279
}
8380

8481
[Test]
8582
public void CanSetConnection()
8683
{
8784
var sb = Sfi.WithOptions();
8885
CanSetConnection(sb);
86+
CanSetConnectionOnStateless(Sfi.WithStatelessOptions());
8987
using (var s = sb.OpenSession())
9088
{
9189
CanSetConnection(s.SessionWithOptions());
90+
CanSetConnectionOnStateless(s.StatelessSessionWithOptions());
9291
}
9392
}
9493

@@ -136,10 +135,8 @@ private void CanSetConnection<T>(T sb) where T : ISessionBuilder<T>
136135
}
137136
}
138137

139-
[Test]
140-
public void CanSetConnectionOnStateless()
138+
private void CanSetConnectionOnStateless<T>(T sb) where T : IStatelessSessionBuilder
141139
{
142-
var sb = Sfi.WithStatelessOptions();
143140
var sbType = sb.GetType().Name;
144141
var conn = Sfi.ConnectionProvider.GetConnection();
145142
try
@@ -150,9 +147,31 @@ public void CanSetConnectionOnStateless()
150147
Assert.AreEqual(conn, options.UserSuppliedConnection, $"{sbType}: After call with a connection");
151148
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with a connection");
152149

153-
fsb = sb.Connection(null);
154-
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with null");
155-
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with null");
150+
if (sb is ISharedStatelessSessionBuilder ssb)
151+
{
152+
var sharedOptions = (ISharedSessionCreationOptions)options;
153+
Assert.IsFalse(sharedOptions.IsTransactionCoordinatorShared, $"{sbType}: Transaction coordinator shared before sharing");
154+
Assert.IsNull(sharedOptions.ConnectionManager, $"{sbType}: Connection manager shared before sharing");
155+
156+
var fssb = ssb.Connection();
157+
// Sharing connection shares the connection manager, not the connection.
158+
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with previous session connection");
159+
Assert.IsTrue(sharedOptions.IsTransactionCoordinatorShared, $"{sbType}: Transaction coordinator not shared after sharing");
160+
Assert.IsNotNull(sharedOptions.ConnectionManager, $"{sbType}: Connection manager not shared after sharing");
161+
Assert.AreEqual(sb, fssb, $"{sbType}: Unexpected fluent return on shared");
162+
163+
fsb = sb.Connection(null);
164+
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with null");
165+
Assert.IsFalse(sharedOptions.IsTransactionCoordinatorShared, $"{sbType}: Transaction coordinator shared after un-sharing");
166+
Assert.IsNull(sharedOptions.ConnectionManager, $"{sbType}: Connection manager shared after un-sharing");
167+
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after un-sharing");
168+
}
169+
else
170+
{
171+
fsb = sb.Connection(null);
172+
Assert.IsNull(options.UserSuppliedConnection, $"{sbType}: After call with null");
173+
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with null");
174+
}
156175
}
157176
finally
158177
{
@@ -259,5 +278,25 @@ private void CanSet<T, V>(T sb, Func<V, T> setter, Func<V> getter, Func<ISharedS
259278
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with {value}");
260279
}
261280
}
281+
282+
private void CanSetOnStateless<T, V>(
283+
T sb, Func<V, T> setter, Func<V> getter, Func<ISharedStatelessSessionBuilder> shared, V initialValue,
284+
params V[] values) where T : IStatelessSessionBuilder
285+
{
286+
var sbType = sb.GetType().Name;
287+
Assert.AreEqual(initialValue, getter(), $"{sbType}: Initial value");
288+
if (shared != null)
289+
{
290+
var fssb = shared();
291+
Assert.AreEqual(values.Last(), getter(), $"{sbType}: After call with shared setting");
292+
Assert.AreEqual(sb, fssb, $"{sbType}: Unexpected fluent return on shared");
293+
}
294+
foreach (var value in values)
295+
{
296+
var fsb = setter(value);
297+
Assert.AreEqual(value, getter(), $"{sbType}: After call with {value}");
298+
Assert.AreEqual(sb, fsb, $"{sbType}: Unexpected fluent return after call with {value}");
299+
}
300+
}
262301
}
263302
}

‎src/NHibernate.Test/TransactionTest/TransactionFixture.cs

+30-1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,35 @@ public void FlushFromTransactionAppliesToSharingSession()
173173
}
174174
}
175175

176+
[Test]
177+
public void FlushFromTransactionAppliesToSharingStatelessSession()
178+
{
179+
using (var s = OpenSession())
180+
{
181+
var builder = s.StatelessSessionWithOptions().Connection();
182+
183+
using (var s1 = builder.OpenStatelessSession())
184+
using (var s2 = builder.OpenStatelessSession())
185+
using (var t = s.BeginTransaction())
186+
{
187+
var p1 = new Person();
188+
var p2 = new Person();
189+
var p3 = new Person();
190+
s1.Insert(p1);
191+
s2.Insert(p2);
192+
s.Save(p3);
193+
t.Commit();
194+
}
195+
}
196+
197+
using (var s = OpenSession())
198+
using (var t = s.BeginTransaction())
199+
{
200+
Assert.That(s.Query<Person>().Count(), Is.EqualTo(3));
201+
t.Commit();
202+
}
203+
}
204+
176205
// Taken and adjusted from NH1632 When_commiting_items_in_DTC_transaction_will_add_items_to_2nd_level_cache
177206
[Test]
178207
public void WhenCommittingItemsWillAddThemTo2ndLevelCache()
@@ -213,4 +242,4 @@ public void WhenCommittingItemsWillAddThemTo2ndLevelCache()
213242
}
214243
}
215244
}
216-
}
245+
}

‎src/NHibernate/Async/ISession.cs

+2
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
using NHibernate.Engine;
1717
using NHibernate.Event;
1818
using NHibernate.Event.Default;
19+
using NHibernate.Impl;
1920
using NHibernate.Stat;
2021
using NHibernate.Type;
2122

2223
namespace NHibernate
2324
{
2425
using System.Threading.Tasks;
2526
using System.Threading;
27+
2628
public partial interface ISession : IDisposable
2729
{
2830

‎src/NHibernate/Async/Impl/AbstractSessionImpl.cs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System;
1212
using System.Collections;
1313
using System.Collections.Generic;
14+
using System.Data;
1415
using System.Data.Common;
1516
using System.Linq;
1617
using NHibernate.AdoNet;

‎src/NHibernate/Async/Impl/SessionImpl.cs

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using System;
1212
using System.Collections;
1313
using System.Collections.Generic;
14-
using System.Data;
1514
using System.Data.Common;
1615
using System.Linq.Expressions;
1716
using System.Runtime.Serialization;

‎src/NHibernate/Async/Impl/StatelessSessionImpl.cs

-3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
using System;
1212
using System.Collections;
1313
using System.Collections.Generic;
14-
using System.Data;
15-
using System.Data.Common;
1614
using System.Linq.Expressions;
17-
using NHibernate.AdoNet;
1815
using NHibernate.Cache;
1916
using NHibernate.Collection;
2017
using NHibernate.Criterion;

‎src/NHibernate/Engine/ISessionImplementor.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,16 @@ public partial interface ISessionImplementor
274274
bool IsOpen { get; }
275275

276276
/// <summary>
277-
/// Is the <c>ISession</c> currently connected?
277+
/// Is the session connected?
278278
/// </summary>
279+
/// <value>
280+
/// <see langword="true" /> if the session is connected.
281+
/// </value>
282+
/// <remarks>
283+
/// A session is considered connected if there is a <see cref="DbConnection"/> (regardless
284+
/// of its state) or if the field <c>connect</c> is true. Meaning that it will connect
285+
/// at the next operation that requires a connection.
286+
/// </remarks>
279287
bool IsConnected { get; }
280288

281289
FlushMode FlushMode { get; set; }

0 commit comments

Comments
 (0)
Please sign in to comment.