@@ -17,6 +17,10 @@ internal record struct QueryKey(object Key, int MetadataToken, ModuleHandle Modu
17
17
18
18
internal class CompiledQueryRunner
19
19
{
20
+ private record struct ClosureTypeInfo ( Type ParameterType , PropertyInfo ValueMemberInfo , FieldInfo [ ] Fields ) ;
21
+
22
+ private static readonly ExtendedExpressionReplacer NoopReplacer = new ( e => e ) ;
23
+
20
24
private readonly Domain domain ;
21
25
private readonly Session session ;
22
26
private readonly QueryEndpoint endpoint ;
@@ -152,47 +156,47 @@ private void AllocateParameterAndReplacer()
152
156
{
153
157
if ( queryTarget == null ) {
154
158
queryParameter = null ;
155
- queryParameterReplacer = new ExtendedExpressionReplacer ( e => e ) ;
159
+ queryParameterReplacer = NoopReplacer ;
156
160
return ;
157
161
}
158
162
159
163
var closureType = queryTarget . GetType ( ) ;
160
- var parameterType = WellKnownOrmTypes . ParameterOfT . CachedMakeGenericType ( closureType ) ;
161
- var valueMemberInfo = parameterType . GetProperty ( nameof ( Parameter < object > . Value ) , closureType ) ;
162
- queryParameter = ( Parameter ) System . Activator . CreateInstance ( parameterType , "pClosure" ) ;
164
+ var info = Memoizer . Get ( closureType , static ct => {
165
+ var parameterType = WellKnownOrmTypes . ParameterOfT . CachedMakeGenericType ( ct ) ;
166
+ return new ClosureTypeInfo (
167
+ parameterType ,
168
+ parameterType . GetProperty ( nameof ( Parameter < object > . Value ) , ct ) ,
169
+ ct . IsClosure ( ) ? ct . GetFields ( ) : null
170
+ ) ;
171
+ } , 10_000 ) ;
172
+ MemberExpression closureAccessor = null ;
173
+ queryParameter = ( Parameter ) System . Activator . CreateInstance ( info . ParameterType , "pClosure" ) ;
163
174
queryParameterReplacer = new ExtendedExpressionReplacer ( expression => {
164
175
if ( expression . NodeType == ExpressionType . Constant ) {
165
- if ( ( expression as ConstantExpression ) . Value == null ) {
166
- return null ;
167
- }
168
- if ( expression . Type . IsClosure ( ) ) {
169
- if ( expression . Type == closureType ) {
170
- return Expression . MakeMemberAccess ( Expression . Constant ( queryParameter , parameterType ) , valueMemberInfo ) ;
171
- }
172
- else {
173
- throw new NotSupportedException ( string . Format (
174
- Strings . ExExpressionDefinedOutsideOfCachingQueryClosure , expression ) ) ;
175
- }
176
+ if ( ( ( ConstantExpression ) expression ) . Value is null ) {
177
+ return null ;
176
178
}
177
179
178
- if ( closureType . DeclaringType == null ) {
179
- if ( expression . Type . IsAssignableFrom ( closureType ) )
180
- return Expression . MakeMemberAccess ( Expression . Constant ( queryParameter , parameterType ) , valueMemberInfo ) ;
180
+ var expressionType = expression . Type ;
181
+ if ( expressionType . IsClosure ( ) ) {
182
+ return expressionType == closureType
183
+ ? GetClosureAccessor ( )
184
+ : throw new NotSupportedException ( string . Format ( Strings . ExExpressionDefinedOutsideOfCachingQueryClosure , expression ) ) ;
181
185
}
182
- else {
183
- if ( expression . Type . IsAssignableFrom ( closureType ) )
184
- return Expression . MakeMemberAccess ( Expression . Constant ( queryParameter , parameterType ) , valueMemberInfo ) ;
185
- if ( expression . Type . IsAssignableFrom ( closureType . DeclaringType ) ) {
186
- var memberInfo = closureType . TryGetFieldInfoFromClosure ( expression . Type ) ;
187
- if ( memberInfo != null )
188
- return Expression . MakeMemberAccess (
189
- Expression . MakeMemberAccess ( Expression . Constant ( queryParameter , parameterType ) , valueMemberInfo ) ,
190
- memberInfo ) ;
191
- }
186
+
187
+ if ( expressionType . IsAssignableFrom ( closureType ) )
188
+ return GetClosureAccessor ( ) ;
189
+ if ( expressionType . IsAssignableFrom ( closureType . DeclaringType )
190
+ && info . Fields ? . FirstOrDefault ( field => field . FieldType == expressionType ) is { } memberInfo ) {
191
+ return Expression . MakeMemberAccess ( GetClosureAccessor ( ) , memberInfo ) ;
192
192
}
193
193
}
194
+
194
195
return null ;
195
196
} ) ;
197
+
198
+ MemberExpression GetClosureAccessor ( ) =>
199
+ closureAccessor ??= Expression . MakeMemberAccess ( Expression . Constant ( queryParameter , info . ParameterType ) , info . ValueMemberInfo ) ;
196
200
}
197
201
198
202
private ParameterizedQuery GetCachedQuery ( ) =>
0 commit comments