@@ -29,36 +29,47 @@ public virtual Expression ApplySelect(FieldSelection selection, QueryClauseBuild
29
29
{
30
30
ArgumentGuard . NotNull ( selection ) ;
31
31
32
- Expression bodyInitializer = CreateLambdaBodyInitializer ( selection , context . ResourceType , context . LambdaScope , false , context ) ;
32
+ Expression bodyInitializer = CreateLambdaBodyInitializer ( selection , context . ResourceType , false , context ) ;
33
33
34
34
LambdaExpression lambda = Expression . Lambda ( bodyInitializer , context . LambdaScope . Parameter ) ;
35
35
36
36
return SelectExtensionMethodCall ( context . ExtensionType , context . Source , context . LambdaScope . Parameter . Type , lambda ) ;
37
37
}
38
38
39
- private Expression CreateLambdaBodyInitializer ( FieldSelection selection , ResourceType resourceType , LambdaScope lambdaScope ,
40
- bool lambdaAccessorRequiresTestForNull , QueryClauseBuilderContext context )
39
+ private Expression CreateLambdaBodyInitializer ( FieldSelection selection , ResourceType resourceType , bool lambdaAccessorRequiresTestForNull ,
40
+ QueryClauseBuilderContext context )
41
41
{
42
+ AssertSameType ( context . LambdaScope . Accessor . Type , resourceType ) ;
43
+
42
44
IReadOnlyEntityType entityType = context . EntityModel . FindEntityType ( resourceType . ClrType ) ! ;
43
45
IReadOnlyEntityType [ ] concreteEntityTypes = entityType . GetConcreteDerivedTypesInclusive ( ) . ToArray ( ) ;
44
46
45
47
Expression bodyInitializer = concreteEntityTypes . Length > 1
46
- ? CreateLambdaBodyInitializerForTypeHierarchy ( selection , resourceType , concreteEntityTypes , lambdaScope , context )
47
- : CreateLambdaBodyInitializerForSingleType ( selection , resourceType , lambdaScope , context ) ;
48
+ ? CreateLambdaBodyInitializerForTypeHierarchy ( selection , resourceType , concreteEntityTypes , context )
49
+ : CreateLambdaBodyInitializerForSingleType ( selection , resourceType , context ) ;
48
50
49
51
if ( ! lambdaAccessorRequiresTestForNull )
50
52
{
51
53
return bodyInitializer ;
52
54
}
53
55
54
- return TestForNull ( lambdaScope . Accessor , bodyInitializer ) ;
56
+ return TestForNull ( context . LambdaScope . Accessor , bodyInitializer ) ;
57
+ }
58
+
59
+ private static void AssertSameType ( Type lambdaAccessorType , ResourceType resourceType )
60
+ {
61
+ if ( lambdaAccessorType != resourceType . ClrType )
62
+ {
63
+ throw new InvalidOperationException (
64
+ $ "Internal error: Mismatch between lambda accessor type '{ lambdaAccessorType . Name } ' and resource type '{ resourceType . ClrType . Name } '.") ;
65
+ }
55
66
}
56
67
57
68
private Expression CreateLambdaBodyInitializerForTypeHierarchy ( FieldSelection selection , ResourceType baseResourceType ,
58
- IEnumerable < IReadOnlyEntityType > concreteEntityTypes , LambdaScope lambdaScope , QueryClauseBuilderContext context )
69
+ IEnumerable < IReadOnlyEntityType > concreteEntityTypes , QueryClauseBuilderContext context )
59
70
{
60
71
IReadOnlySet < ResourceType > resourceTypes = selection . GetResourceTypes ( ) ;
61
- Expression rootCondition = lambdaScope . Accessor ;
72
+ Expression rootCondition = context . LambdaScope . Accessor ;
62
73
63
74
foreach ( IReadOnlyEntityType entityType in concreteEntityTypes )
64
75
{
@@ -73,14 +84,14 @@ private Expression CreateLambdaBodyInitializerForTypeHierarchy(FieldSelection se
73
84
Dictionary < PropertyInfo , PropertySelector > . ValueCollection propertySelectors =
74
85
ToPropertySelectors ( fieldSelectors , resourceType , entityType . ClrType , context . EntityModel ) ;
75
86
76
- MemberBinding [ ] propertyAssignments = propertySelectors . Select ( selector => CreatePropertyAssignment ( selector , lambdaScope , context ) )
87
+ MemberBinding [ ] propertyAssignments = propertySelectors . Select ( selector => CreatePropertyAssignment ( selector , context ) )
77
88
. Cast < MemberBinding > ( ) . ToArray ( ) ;
78
89
79
90
NewExpression createInstance = _resourceFactory . CreateNewExpression ( entityType . ClrType ) ;
80
91
MemberInitExpression memberInit = Expression . MemberInit ( createInstance , propertyAssignments ) ;
81
92
UnaryExpression castToBaseType = Expression . Convert ( memberInit , baseResourceType . ClrType ) ;
82
93
83
- BinaryExpression typeCheck = CreateRuntimeTypeCheck ( lambdaScope , entityType . ClrType ) ;
94
+ BinaryExpression typeCheck = CreateRuntimeTypeCheck ( context . LambdaScope , entityType . ClrType ) ;
84
95
rootCondition = Expression . Condition ( typeCheck , castToBaseType , rootCondition ) ;
85
96
}
86
97
}
@@ -100,18 +111,16 @@ private static BinaryExpression CreateRuntimeTypeCheck(LambdaScope lambdaScope,
100
111
return Expression . MakeBinary ( ExpressionType . Equal , getTypeCall , concreteTypeConstant , false , TypeOpEqualityMethod ) ;
101
112
}
102
113
103
- private MemberInitExpression CreateLambdaBodyInitializerForSingleType ( FieldSelection selection , ResourceType resourceType , LambdaScope lambdaScope ,
114
+ private MemberInitExpression CreateLambdaBodyInitializerForSingleType ( FieldSelection selection , ResourceType resourceType ,
104
115
QueryClauseBuilderContext context )
105
116
{
106
117
FieldSelectors fieldSelectors = selection . GetOrCreateSelectors ( resourceType ) ;
107
118
108
119
Dictionary < PropertyInfo , PropertySelector > . ValueCollection propertySelectors =
109
- ToPropertySelectors ( fieldSelectors , resourceType , lambdaScope . Accessor . Type , context . EntityModel ) ;
110
-
111
- MemberBinding [ ] propertyAssignments = propertySelectors . Select ( selector => CreatePropertyAssignment ( selector , lambdaScope , context ) )
112
- . Cast < MemberBinding > ( ) . ToArray ( ) ;
120
+ ToPropertySelectors ( fieldSelectors , resourceType , context . LambdaScope . Accessor . Type , context . EntityModel ) ;
113
121
114
- NewExpression createInstance = _resourceFactory . CreateNewExpression ( lambdaScope . Accessor . Type ) ;
122
+ MemberBinding [ ] propertyAssignments = propertySelectors . Select ( selector => CreatePropertyAssignment ( selector , context ) ) . Cast < MemberBinding > ( ) . ToArray ( ) ;
123
+ NewExpression createInstance = _resourceFactory . CreateNewExpression ( context . LambdaScope . Accessor . Type ) ;
115
124
return Expression . MemberInit ( createInstance , propertyAssignments ) ;
116
125
}
117
126
@@ -182,50 +191,56 @@ private static void IncludeEagerLoads(ResourceType resourceType, Dictionary<Prop
182
191
}
183
192
}
184
193
185
- private MemberAssignment CreatePropertyAssignment ( PropertySelector propertySelector , LambdaScope lambdaScope , QueryClauseBuilderContext context )
194
+ private MemberAssignment CreatePropertyAssignment ( PropertySelector propertySelector , QueryClauseBuilderContext context )
186
195
{
187
- bool requiresUpCast = lambdaScope . Accessor . Type != propertySelector . Property . DeclaringType &&
188
- lambdaScope . Accessor . Type . IsAssignableFrom ( propertySelector . Property . DeclaringType ) ;
196
+ bool requiresUpCast = context . LambdaScope . Accessor . Type != propertySelector . Property . DeclaringType &&
197
+ context . LambdaScope . Accessor . Type . IsAssignableFrom ( propertySelector . Property . DeclaringType ) ;
198
+
199
+ UnaryExpression ? derivedAccessor = requiresUpCast ? Expression . Convert ( context . LambdaScope . Accessor , propertySelector . Property . DeclaringType ! ) : null ;
189
200
190
- MemberExpression propertyAccess = requiresUpCast
191
- ? Expression . MakeMemberAccess ( Expression . Convert ( lambdaScope . Accessor , propertySelector . Property . DeclaringType ! ) , propertySelector . Property )
192
- : Expression . Property ( lambdaScope . Accessor , propertySelector . Property ) ;
201
+ MemberExpression propertyAccess = derivedAccessor != null
202
+ ? Expression . MakeMemberAccess ( derivedAccessor , propertySelector . Property )
203
+ : Expression . Property ( context . LambdaScope . Accessor , propertySelector . Property ) ;
193
204
194
205
Expression assignmentRightHandSide = propertyAccess ;
195
206
196
207
if ( propertySelector . NextLayer != null )
197
208
{
198
- assignmentRightHandSide =
199
- CreateAssignmentRightHandSideForLayer ( propertySelector . NextLayer , lambdaScope , propertyAccess , propertySelector . Property , context ) ;
209
+ QueryClauseBuilderContext rightHandSideContext =
210
+ derivedAccessor != null ? context . WithLambdaScope ( context . LambdaScope . WithAccessor ( derivedAccessor ) ) : context ;
211
+
212
+ assignmentRightHandSide = CreateAssignmentRightHandSideForLayer ( propertySelector . NextLayer , propertyAccess ,
213
+ propertySelector . Property , rightHandSideContext ) ;
200
214
}
201
215
202
216
return Expression . Bind ( propertySelector . Property , assignmentRightHandSide ) ;
203
217
}
204
218
205
- private Expression CreateAssignmentRightHandSideForLayer ( QueryLayer layer , LambdaScope outerLambdaScope , MemberExpression propertyAccess ,
206
- PropertyInfo selectorPropertyInfo , QueryClauseBuilderContext context )
219
+ private Expression CreateAssignmentRightHandSideForLayer ( QueryLayer layer , MemberExpression propertyAccess , PropertyInfo selectorPropertyInfo ,
220
+ QueryClauseBuilderContext context )
207
221
{
208
222
Type ? collectionElementType = CollectionConverter . Instance . FindCollectionElementType ( selectorPropertyInfo . PropertyType ) ;
209
223
Type bodyElementType = collectionElementType ?? selectorPropertyInfo . PropertyType ;
210
224
211
225
if ( collectionElementType != null )
212
226
{
213
- return CreateCollectionInitializer ( outerLambdaScope , selectorPropertyInfo , bodyElementType , layer , context ) ;
227
+ return CreateCollectionInitializer ( selectorPropertyInfo , bodyElementType , layer , context ) ;
214
228
}
215
229
216
230
if ( layer . Selection == null || layer . Selection . IsEmpty )
217
231
{
218
232
return propertyAccess ;
219
233
}
220
234
221
- using LambdaScope scope = context . LambdaScopeFactory . CreateScope ( bodyElementType , propertyAccess ) ;
222
- return CreateLambdaBodyInitializer ( layer . Selection , layer . ResourceType , scope , true , context ) ;
235
+ using LambdaScope initializerScope = context . LambdaScopeFactory . CreateScope ( bodyElementType , propertyAccess ) ;
236
+ QueryClauseBuilderContext initializerContext = context . WithLambdaScope ( initializerScope ) ;
237
+ return CreateLambdaBodyInitializer ( layer . Selection , layer . ResourceType , true , initializerContext ) ;
223
238
}
224
239
225
- private static MethodCallExpression CreateCollectionInitializer ( LambdaScope lambdaScope , PropertyInfo collectionProperty , Type elementType ,
226
- QueryLayer layer , QueryClauseBuilderContext context )
240
+ private static MethodCallExpression CreateCollectionInitializer ( PropertyInfo collectionProperty , Type elementType , QueryLayer layer ,
241
+ QueryClauseBuilderContext context )
227
242
{
228
- MemberExpression propertyExpression = Expression . Property ( lambdaScope . Accessor , collectionProperty ) ;
243
+ MemberExpression propertyExpression = Expression . Property ( context . LambdaScope . Accessor , collectionProperty ) ;
229
244
230
245
var nestedContext = new QueryableBuilderContext ( propertyExpression , elementType , typeof ( Enumerable ) , context . EntityModel , context . LambdaScopeFactory ,
231
246
context . State ) ;
0 commit comments