Skip to content

Commit 193bfb9

Browse files
Fix thread safety issue in Loader
1 parent 683df95 commit 193bfb9

File tree

2 files changed

+17
-16
lines changed

2 files changed

+17
-16
lines changed

src/NHibernate/Async/Loader/Loader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
using System;
1212
using System.Collections;
13+
using System.Collections.Concurrent;
1314
using System.Collections.Generic;
1415
using System.Data;
1516
using System.Data.Common;

src/NHibernate/Loader/Loader.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Concurrent;
34
using System.Collections.Generic;
45
using System.Data;
56
using System.Data.Common;
@@ -31,17 +32,21 @@ namespace NHibernate.Loader
3132
/// Abstract superclass of object loading (and querying) strategies.
3233
/// </summary>
3334
/// <remarks>
34-
/// <p>
35+
/// <para>
3536
/// This class implements useful common functionality that concrete loaders would delegate to.
3637
/// It is not intended that this functionality would be directly accessed by client code (Hence,
3738
/// all methods of this class are declared <c>protected</c> or <c>private</c>.) This class relies heavily upon the
38-
/// <see cref="ILoadable" /> interface, which is the contract between this class and
39+
/// <see cref="ILoadable" /> interface, which is the contract between this class and
3940
/// <see cref="IEntityPersister" />s that may be loaded by it.
40-
/// </p>
41-
/// <p>
42-
/// The present implementation is able to load any number of columns of entities and at most
41+
/// </para>
42+
/// <para>
43+
/// The present implementation is able to load any number of columns of entities and at most
4344
/// one collection role per query.
44-
/// </p>
45+
/// </para>
46+
/// <para>
47+
/// All this class members are thread safe. Entity and collection loaders are held in persisters shared among
48+
/// sessions built from the same session factory. They must be thread safe.
49+
/// </para>
4550
/// </remarks>
4651
/// <seealso cref="NHibernate.Persister.Entity.ILoadable"/>
4752
public abstract partial class Loader
@@ -63,8 +68,8 @@ public abstract partial class Loader
6368
/// <summary>
6469
/// Caches subclass entity aliases for given persister index in <see cref="EntityPersisters"/> and subclass entity name
6570
/// </summary>
66-
private readonly Dictionary<Tuple<int, string>, string[][]> _subclassEntityAliasesMap = new Dictionary<Tuple<int, string>, string[][]>();
67-
71+
private readonly ConcurrentDictionary<Tuple<int, string>, string[][]> _subclassEntityAliasesMap = new ConcurrentDictionary<Tuple<int, string>, string[][]>();
72+
6873
protected Loader(ISessionFactoryImplementor factory)
6974
{
7075
_factory = factory;
@@ -1103,14 +1108,9 @@ private void LoadFromResultSet(DbDataReader rs, int i, object obj, string instan
11031108
private string[][] GetSubclassEntityAliases(int i, ILoadable persister)
11041109
{
11051110
var cacheKey = System.Tuple.Create(i, persister.EntityName);
1106-
if (_subclassEntityAliasesMap.TryGetValue(cacheKey, out string[][] cols))
1107-
{
1108-
return cols;
1109-
}
1110-
1111-
cols = EntityAliases[i].GetSuffixedPropertyAliases(persister);
1112-
_subclassEntityAliasesMap[cacheKey] = cols;
1113-
return cols;
1111+
return _subclassEntityAliasesMap.GetOrAdd(
1112+
cacheKey,
1113+
k => EntityAliases[i].GetSuffixedPropertyAliases(persister));
11141114
}
11151115

11161116
/// <summary>

0 commit comments

Comments
 (0)