Skip to content

Commit f2bb2c2

Browse files
authored
Optimize .Query.All<> implementation (#410)
* Optimize `.Query.All<>` implementation * Move RootCallExpressionsCache * rename to AllExpression
1 parent 97a1cdd commit f2bb2c2

File tree

3 files changed

+24
-41
lines changed

3 files changed

+24
-41
lines changed

Orm/Xtensive.Orm/Orm/Domain.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44
// Created by: Dmitri Maximov
55
// Created: 2007.08.03
66

7-
using System;
87
using System.Collections.Concurrent;
9-
using System.Collections.Generic;
108
using System.Runtime.ExceptionServices;
11-
using System.Threading;
12-
using System.Threading.Tasks;
139
using JetBrains.Annotations;
1410
using Xtensive.Caching;
1511
using Xtensive.Collections;
@@ -132,8 +128,6 @@ public static Domain Demand()
132128

133129
internal FastConcurrentLruCache<QueryKey, (QueryKey Key, ParameterizedQuery Query)> QueryCache { get; }
134130

135-
internal ConcurrentDictionary<Type, System.Linq.Expressions.MethodCallExpression> RootCallExpressionsCache { get; } = new();
136-
137131
/// <summary>
138132
/// Caches uncompiled queries used by <see cref="PrefetchManager"/> to fetch certain entities.
139133
/// </summary>

Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
// Created by: Denis Krjuchkov
55
// Created: 2009.04.02
66

7-
using System;
8-
using System.Collections.Generic;
9-
using System.Diagnostics;
10-
using System.Linq;
7+
using System.Collections.Concurrent;
118
using System.Linq.Expressions;
129
using System.Reflection;
1310
using Xtensive.Core;
@@ -66,10 +63,10 @@ public static Expression<Func<Tuple, bool>> BuildFilterLambda(int startIndex, IR
6663
return FastExpression.Lambda<Func<Tuple, bool>>(filterExpression, TupleParameters);
6764
}
6865

69-
private static Expression CreateEntityQuery(Type elementType, Domain domain)
70-
{
71-
return domain.RootCallExpressionsCache.GetOrAdd(elementType, (t) => Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(elementType)));
72-
}
66+
private static readonly ConcurrentDictionary<Type, MethodCallExpression> RootCallExpressionsCache = new();
67+
68+
internal static Expression CreateEntityQuery(Type elementType) =>
69+
RootCallExpressionsCache.GetOrAdd(elementType, static t => Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(t)));
7370

7471
public static bool IsDirectEntitySetQuery(Expression entitySet)
7572
{
@@ -134,7 +131,7 @@ public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo
134131
);
135132
return Expression.Call(
136133
WellKnownMembers.Queryable.Where.CachedMakeGenericMethod(elementType),
137-
CreateEntityQuery(elementType, domain),
134+
CreateEntityQuery(elementType),
138135
FastExpression.Lambda(whereExpression, whereParameter)
139136
);
140137
}
@@ -159,7 +156,7 @@ public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo
159156

160157
var outerQuery = Expression.Call(
161158
WellKnownMembers.Queryable.Where.CachedMakeGenericMethod(connectorType),
162-
CreateEntityQuery(connectorType, domain),
159+
CreateEntityQuery(connectorType),
163160
FastExpression.Lambda(filterExpression, filterParameter)
164161
);
165162

@@ -171,7 +168,7 @@ public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo
171168
var innerSelector = FastExpression.Lambda(innerSelectorParameter, innerSelectorParameter);
172169
var resultSelector = FastExpression.Lambda(innerSelectorParameter, outerSelectorParameter, innerSelectorParameter);
173170

174-
var innerQuery = CreateEntityQuery(elementType, domain);
171+
var innerQuery = CreateEntityQuery(elementType);
175172
var joinMethodInfo = WellKnownMembers.Queryable.Join
176173
.MakeGenericMethod(new[] {
177174
connectorType,

Orm/Xtensive.Orm/Orm/QueryEndpoint.cs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44

5-
using System;
6-
using System.Collections.Generic;
7-
using System.Linq;
85
using System.Linq.Expressions;
96
using System.Reflection;
10-
using System.Threading;
11-
using System.Threading.Tasks;
127
using JetBrains.Annotations;
138
using Xtensive.Core;
149
using Xtensive.Orm.FullTextSearchCondition.Interfaces;
1510
using Xtensive.Orm.FullTextSearchCondition.Nodes;
1611
using Xtensive.Orm.Internals;
17-
using Xtensive.Orm.Internals.Prefetch;
1812
using Xtensive.Orm.Linq;
1913
using Xtensive.Reflection;
2014
using Tuple = Xtensive.Tuples.Tuple;
@@ -51,7 +45,13 @@ public bool Equals(QueryEndpoint other) =>
5145

5246
public override int GetHashCode() => HashCode.Combine(Provider, RootBuilder);
5347

54-
/// <summary>
48+
private static class Traits<T>
49+
{
50+
public static readonly MethodCallExpression RootCallExpression =
51+
Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(typeof(T)));
52+
}
53+
54+
/// <summary>
5555
/// The "starting point" for any LINQ query -
5656
/// a <see cref="IQueryable{T}"/> enumerating all the instances
5757
/// of type <typeparamref name="T"/>.
@@ -61,11 +61,10 @@ public bool Equals(QueryEndpoint other) =>
6161
/// An <see cref="IQueryable{T}"/> enumerating all the instances
6262
/// of type <typeparamref name="T"/>.
6363
/// </returns>
64-
public IQueryable<T> All<T>()
65-
where T : class, IEntity
66-
{
67-
return Provider.CreateQuery<T>(BuildRootExpression(typeof(T)));
68-
}
64+
public IQueryable<T> All<T>() where T : class, IEntity =>
65+
Provider.CreateQuery<T>(RootBuilder != null
66+
? RootBuilder.BuildRootExpression(typeof(T))
67+
: Traits<T>.RootCallExpression);
6968

7069
/// <summary>
7170
/// The "starting point" for dynamic LINQ query -
@@ -77,10 +76,11 @@ public IQueryable<T> All<T>()
7776
/// An <see cref="IQueryable"/> enumerating all the instances
7877
/// of type <paramref name="elementType"/>.
7978
/// </returns>
80-
public IQueryable All(Type elementType)
81-
{
82-
return ((IQueryProvider) Provider).CreateQuery(BuildRootExpression(elementType));
83-
}
79+
public IQueryable All(Type elementType) =>
80+
((IQueryProvider) Provider).CreateQuery(RootBuilder != null
81+
? RootBuilder.BuildRootExpression(elementType)
82+
: QueryHelper.CreateEntityQuery(elementType)
83+
);
8484

8585
#region Full-text related
8686

@@ -970,13 +970,6 @@ private Key GetKeyByValues<T>(ReadOnlySpan<object> keyValues)
970970
return Key.Create(session.Domain, session.StorageNodeId, session.Domain.Model.Types[typeof(T)], TypeReferenceAccuracy.BaseType, keyValues);
971971
}
972972

973-
private Expression BuildRootExpression(Type elementType)
974-
{
975-
return RootBuilder!=null
976-
? RootBuilder.BuildRootExpression(elementType)
977-
: Session.Domain.RootCallExpressionsCache.GetOrAdd(elementType, (t) => Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(t)));
978-
}
979-
980973
private static void ThrowKeyNotFoundException(Key key) =>
981974
throw new KeyNotFoundException(String.Format(Strings.EntityWithKeyXDoesNotExist, key));
982975

@@ -987,7 +980,6 @@ private static void ThrowKeyNotFoundException(Key key) =>
987980

988981
internal QueryEndpoint(QueryProvider provider)
989982
{
990-
ArgumentNullException.ThrowIfNull(provider);
991983
Provider = provider;
992984
}
993985

0 commit comments

Comments
 (0)