Skip to content

Commit 3ba9438

Browse files
NH-4032 - Multiple factories in thread static context.
1 parent b92fd5f commit 3ba9438

File tree

4 files changed

+100
-9
lines changed

4 files changed

+100
-9
lines changed

doc/reference/modules/architecture.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@
259259
<listitem>
260260
<para>
261261
<literal>NHibernate.Context.ThreadStaticSessionContext</literal> - current session is
262-
stored in a thread-static variable. This context only supports one session factory.
262+
stored in a thread-static variable. This context supports multiple session factory only
263+
since NHibernate v5.
263264
You are responsible to bind and unbind an <literal>ISession</literal> instance with
264265
static methods of class <literal>CurrentSessionContext</literal>.
265266
</para>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System.Collections;
2+
using System.Threading;
3+
using NHibernate.Cfg;
4+
using NHibernate.Context;
5+
using NHibernate.Engine;
6+
using NUnit.Framework;
7+
8+
namespace NHibernate.Test.ConnectionTest
9+
{
10+
[TestFixture]
11+
public class ThreadStaticSessionContextFixture : ConnectionManagementTestCase
12+
{
13+
protected override ISession GetSessionUnderTest()
14+
{
15+
var session = OpenSession();
16+
session.BeginTransaction();
17+
return session;
18+
}
19+
20+
protected override void Configure(Configuration configuration)
21+
{
22+
base.Configure(cfg);
23+
cfg.SetProperty(Environment.CurrentSessionContextClass, "thread_static");
24+
}
25+
26+
[Test]
27+
public void ThreadStaticIsolation()
28+
{
29+
using (var session1 = OpenSession())
30+
using (var session2 = OpenSession())
31+
{
32+
var thread1 = new Thread(() =>
33+
{
34+
for (var i = 1; i <= 100; i++)
35+
{
36+
CurrentSessionContext.Bind(session1);
37+
Thread.Sleep(1);
38+
// Yes, NUnit catches asserts inside threads.
39+
AssertCurrentSession(Sfi, session1, $"At iteration {i}, unexpected session for thread 1.");
40+
}
41+
});
42+
43+
var thread2 = new Thread(() =>
44+
{
45+
for (var i = 1; i <= 34; i++)
46+
{
47+
CurrentSessionContext.Bind(session2);
48+
// Have a different longer sleep for ensuring the other thread have changed its own.
49+
Thread.Sleep(3);
50+
AssertCurrentSession(Sfi, session2, $"At iteration {i}, unexpected session for thread 2.");
51+
}
52+
});
53+
54+
thread1.Start();
55+
thread2.Start();
56+
thread1.Join();
57+
thread2.Join();
58+
}
59+
}
60+
61+
[Test]
62+
public void ThreadStaticMultiFactory()
63+
{
64+
using (var factory1 = cfg.BuildSessionFactory())
65+
using (var session1 = factory1.OpenSession())
66+
using (var factory2 = cfg.BuildSessionFactory())
67+
using (var session2 = factory2.OpenSession())
68+
{
69+
CurrentSessionContext.Bind(session1);
70+
AssertCurrentSession(factory1, session1, "Unexpected session for factory1 after bind of session1.");
71+
CurrentSessionContext.Bind(session2);
72+
AssertCurrentSession(factory2, session2, "Unexpected session for factory2 after bind of session2.");
73+
AssertCurrentSession(factory1, session1, "Unexpected session for factory1 after bind of session2.");
74+
}
75+
}
76+
77+
private void AssertCurrentSession(ISessionFactory factory, ISession session, string message)
78+
{
79+
Assert.That(
80+
factory.GetCurrentSession(),
81+
Is.EqualTo(session),
82+
"{0} {1} instead of {2}.", message,
83+
factory.GetCurrentSession().GetSessionImplementation().SessionId,
84+
session.GetSessionImplementation().SessionId);
85+
}
86+
}
87+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
<Compile Include="ConnectionTest\AggressiveReleaseTest.cs" />
210210
<Compile Include="ConnectionTest\ConnectionManagementTestCase.cs" />
211211
<Compile Include="ConnectionTest\AsyncLocalSessionContextFixture.cs" />
212+
<Compile Include="ConnectionTest\ThreadStaticSessionContextFixture.cs" />
212213
<Compile Include="ConnectionTest\YetAnother.cs" />
213214
<Compile Include="ConnectionTest\Other.cs" />
214215
<Compile Include="ConnectionTest\Silly.cs" />
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
using System;
2+
using System.Collections;
3+
using NHibernate.Engine;
24

35
namespace NHibernate.Context
46
{
57
/// <summary>
68
/// Provides a <see cref="ISessionFactory.GetCurrentSession()">current session</see>
79
/// for each thread using the [<see cref="ThreadStaticAttribute"/>].
8-
/// To avoid if there are two session factories in the same thread.
910
/// </summary>
1011
[Serializable]
11-
public class ThreadStaticSessionContext : CurrentSessionContext
12+
public class ThreadStaticSessionContext : MapBasedSessionContext
1213
{
1314
[ThreadStatic]
14-
private static ISession _session;
15+
private static IDictionary _map;
1516

16-
public ThreadStaticSessionContext(Engine.ISessionFactoryImplementor factory)
17+
public ThreadStaticSessionContext(ISessionFactoryImplementor factory) : base (factory) { }
18+
19+
protected override IDictionary GetMap()
1720
{
21+
return _map;
1822
}
1923

20-
/// <summary> Gets or sets the currently bound session. </summary>
21-
protected override ISession Session
24+
protected override void SetMap(IDictionary value)
2225
{
23-
get { return _session; }
24-
set { _session = value; }
26+
_map = value;
2527
}
2628
}
2729
}

0 commit comments

Comments
 (0)