11using System ;
22using System . Collections ;
3+ using System . Collections . Concurrent ;
34using System . Collections . Generic ;
45using System . Data ;
56using 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