Skip to content

Commit a58a56c

Browse files
Replace an O(n) lookup in LINQ query parsing by an O(1) one
The HQL generators registry already uses dictionaries to resolve generators for methods found in LINQ expression. But some generators do not declare statically their supported methods and instead have to be queried with a loop on them for support of methods encountered in the LINQ query. The result of this lookup can be cached for avoiding calling this loop again on the next query using the method. If #1868 is merged, this change will compensate for #1868 causing up to three such lookups by method.
1 parent fe440a0 commit a58a56c

File tree

2 files changed

+16
-10
lines changed

2 files changed

+16
-10
lines changed

src/NHibernate.Test/Async/Hql/HQLFunctions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1079,9 +1079,9 @@ public async Task Current_DateAsync()
10791079
public async Task Current_Date_IsLowestTimeOfDayAsync()
10801080
{
10811081
AssumeFunctionSupported("current_date");
1082-
var now = DateTime.Now;
10831082
if (!TestDialect.SupportsNonDataBoundCondition)
10841083
Assert.Ignore("Test is not supported by the target database");
1084+
var now = DateTime.Now;
10851085
if (now.TimeOfDay < TimeSpan.FromMinutes(5) || now.TimeOfDay > TimeSpan.Parse("23:55"))
10861086
Assert.Ignore("Test is unreliable around midnight");
10871087

src/NHibernate/Linq/Functions/DefaultLinqToHqlGeneratorsRegistry.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Concurrent;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Reflection;
45

@@ -10,6 +11,9 @@ public class DefaultLinqToHqlGeneratorsRegistry : ILinqToHqlGeneratorsRegistry
1011
private readonly Dictionary<MemberInfo, IHqlGeneratorForProperty> registeredProperties = new Dictionary<MemberInfo, IHqlGeneratorForProperty>();
1112
private readonly List<IRuntimeMethodHqlGenerator> runtimeMethodHqlGenerators = new List<IRuntimeMethodHqlGenerator>();
1213

14+
private readonly ConcurrentDictionary<MethodInfo, IHqlGeneratorForMethod> _cachedRuntimeMethodHqlGenerators =
15+
new ConcurrentDictionary<MethodInfo, IHqlGeneratorForMethod>();
16+
1317
public DefaultLinqToHqlGeneratorsRegistry()
1418
{
1519
RegisterGenerator(new StandardLinqExtensionMethodGenerator());
@@ -69,14 +73,15 @@ public DefaultLinqToHqlGeneratorsRegistry()
6973

7074
protected bool GetRuntimeMethodGenerator(MethodInfo method, out IHqlGeneratorForMethod methodGenerator)
7175
{
72-
methodGenerator = null;
73-
74-
foreach (var typeGenerator in runtimeMethodHqlGenerators.Where(typeGenerator => typeGenerator.SupportsMethod(method)))
75-
{
76-
methodGenerator = typeGenerator.GetMethodGenerator(method);
77-
return true;
78-
}
79-
return false;
76+
methodGenerator = _cachedRuntimeMethodHqlGenerators.GetOrAdd(
77+
method,
78+
m =>
79+
runtimeMethodHqlGenerators
80+
.Where(g => g.SupportsMethod(m))
81+
.Select(g => g.GetMethodGenerator(m))
82+
.FirstOrDefault());
83+
84+
return methodGenerator != null;
8085
}
8186

8287
public virtual bool TryGetGenerator(MethodInfo method, out IHqlGeneratorForMethod generator)
@@ -112,6 +117,7 @@ public virtual void RegisterGenerator(MemberInfo property, IHqlGeneratorForPrope
112117
public void RegisterGenerator(IRuntimeMethodHqlGenerator generator)
113118
{
114119
runtimeMethodHqlGenerators.Add(generator);
120+
_cachedRuntimeMethodHqlGenerators.Clear();
115121
}
116122
}
117123
}

0 commit comments

Comments
 (0)