Skip to content

Commit 1015c2a

Browse files
Add GetOrAdd on the session factory factory
fix #3657
1 parent 916c6dc commit 1015c2a

File tree

4 files changed

+102
-3
lines changed

4 files changed

+102
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH3657
4+
{
5+
class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using log4net;
2+
using NHibernate.Cfg;
3+
using NHibernate.Impl;
4+
using NUnit.Framework;
5+
6+
namespace NHibernate.Test.NHSpecificTest.GH3657
7+
{
8+
[TestFixture]
9+
public class Fixture
10+
{
11+
private static readonly ILog _log = LogManager.GetLogger(typeof(Fixture));
12+
private const string TestSessionFactoryName = "TestName";
13+
14+
private Configuration _cfg;
15+
private ISessionFactory _builtSessionFactory;
16+
17+
[OneTimeSetUp]
18+
public void TestFixtureSetUp()
19+
{
20+
_cfg = TestConfigurationHelper.GetDefaultConfiguration();
21+
var type = GetType();
22+
_cfg.AddResource(type.Namespace + ".Mappings.hbm.xml", type.Assembly);
23+
_cfg.SetProperty(Environment.SessionFactoryName, TestSessionFactoryName);
24+
}
25+
26+
[TearDown]
27+
public void TearDown()
28+
{
29+
_builtSessionFactory?.Dispose();
30+
_builtSessionFactory = null;
31+
}
32+
33+
private ISessionFactory SessionFactoryBuilder()
34+
{
35+
Assert.That(_builtSessionFactory, Is.Null, "SessionFactory was already built");
36+
37+
_builtSessionFactory = _cfg.BuildSessionFactory();
38+
_log.Info("Successfully built session factory");
39+
40+
return _builtSessionFactory;
41+
}
42+
43+
[Test]
44+
public void GetOrAddTwice()
45+
{
46+
var factory = SessionFactoryObjectFactory.GetOrAddNamedInstance(TestSessionFactoryName, SessionFactoryBuilder);
47+
Assert.That(factory, Is.Not.Null, "Failed to get the factory once");
48+
49+
var factory2 = SessionFactoryObjectFactory.GetOrAddNamedInstance(TestSessionFactoryName, SessionFactoryBuilder);
50+
Assert.That(factory2, Is.Not.Null, "Failed to get the factory twice");
51+
Assert.That(factory, Is.SameAs(factory2), "The two factories should be the same");
52+
}
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
3+
namespace="NHibernate.Test.NHSpecificTest.GH3657">
4+
5+
<class name="Entity">
6+
<id name="Id" generator="guid.comb"/>
7+
<property name="Name"/>
8+
</class>
9+
10+
</hibernate-mapping>

src/NHibernate/Impl/SessionFactoryObjectFactory.cs

+28-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Runtime.CompilerServices;
34

@@ -78,16 +79,40 @@ public static void RemoveInstance(string uid, string name, IDictionary<string, s
7879
}
7980

8081
/// <summary>
81-
/// Returns a Named Instance of the SessionFactory from the local "cache" identified by name.
82+
/// Get an instance of the SessionFactory from the local "cache" identified by name if it
83+
/// exists, otherwise run the provided factory and return its result.
8284
/// </summary>
8385
/// <param name="name">The name of the ISessionFactory.</param>
86+
/// <param name="instanceFactory">The ISessionFactory factory to use if the instance is not
87+
/// found.</param>
8488
/// <returns>An instantiated ISessionFactory.</returns>
89+
/// <remarks>It is the caller responsibility to ensure <paramref name="instanceFactory"/>
90+
/// will add and yield a session factory of the requested <paramref name="name"/>.</remarks>
91+
[MethodImpl(MethodImplOptions.Synchronized)]
92+
public static ISessionFactory GetOrAddNamedInstance(string name, Func<ISessionFactory> instanceFactory)
93+
{
94+
if (instanceFactory == null)
95+
throw new ArgumentNullException(nameof(instanceFactory));
96+
97+
if (NamedInstances.TryGetValue(name, out var factory))
98+
return factory;
99+
return instanceFactory();
100+
}
101+
102+
/// <summary>
103+
/// Returns a Named Instance of the SessionFactory from the local "cache" identified by name.
104+
/// </summary>
105+
/// <param name="name">The name of the ISessionFactory.</param>
106+
/// <returns>An ISessionFactory if found, <see langword="null" /> otherwise.</returns>
107+
/// <remarks>If the session factory instantiation is performed concurrently, this method
108+
/// may yield an instance of it still being built, which may lead to threading issues.
109+
/// Use <see cref="GetOrAddNamedInstance(string, Func{ISessionFactory})" /> instead in such case.</remarks>
85110
[MethodImpl(MethodImplOptions.Synchronized)]
86111
public static ISessionFactory GetNamedInstance(string name)
87112
{
88113
log.Debug("lookup: name={0}", name);
89114
ISessionFactory factory;
90-
bool found=NamedInstances.TryGetValue(name, out factory);
115+
bool found = NamedInstances.TryGetValue(name, out factory);
91116
if (!found)
92117
{
93118
log.Warn("Not found: {0}", name);
@@ -99,7 +124,7 @@ public static ISessionFactory GetNamedInstance(string name)
99124
/// Returns an Instance of the SessionFactory from the local "cache" identified by UUID.
100125
/// </summary>
101126
/// <param name="uid">The identifier of the ISessionFactory.</param>
102-
/// <returns>An instantiated ISessionFactory.</returns>
127+
/// <returns>An ISessionFactory if found, <see langword="null" /> otherwise.</returns>
103128
[MethodImpl(MethodImplOptions.Synchronized)]
104129
public static ISessionFactory GetInstance(string uid)
105130
{

0 commit comments

Comments
 (0)