@@ -29,36 +29,47 @@ public virtual Expression ApplySelect(FieldSelection selection, QueryClauseBuild
2929 {
3030 ArgumentGuard . NotNull ( selection ) ;
3131
32- Expression bodyInitializer = CreateLambdaBodyInitializer ( selection , context . ResourceType , context . LambdaScope , false , context ) ;
32+ Expression bodyInitializer = CreateLambdaBodyInitializer ( selection , context . ResourceType , false , context ) ;
3333
3434 LambdaExpression lambda = Expression . Lambda ( bodyInitializer , context . LambdaScope . Parameter ) ;
3535
3636 return SelectExtensionMethodCall ( context . ExtensionType , context . Source , context . LambdaScope . Parameter . Type , lambda ) ;
3737 }
3838
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 )
4141 {
42+ AssertSameType ( context . LambdaScope . Accessor . Type , resourceType ) ;
43+
4244 IReadOnlyEntityType entityType = context . EntityModel . FindEntityType ( resourceType . ClrType ) ! ;
4345 IReadOnlyEntityType [ ] concreteEntityTypes = entityType . GetConcreteDerivedTypesInclusive ( ) . ToArray ( ) ;
4446
4547 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 ) ;
4850
4951 if ( ! lambdaAccessorRequiresTestForNull )
5052 {
5153 return bodyInitializer ;
5254 }
5355
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+ }
5566 }
5667
5768 private Expression CreateLambdaBodyInitializerForTypeHierarchy ( FieldSelection selection , ResourceType baseResourceType ,
58- IEnumerable < IReadOnlyEntityType > concreteEntityTypes , LambdaScope lambdaScope , QueryClauseBuilderContext context )
69+ IEnumerable < IReadOnlyEntityType > concreteEntityTypes , QueryClauseBuilderContext context )
5970 {
6071 IReadOnlySet < ResourceType > resourceTypes = selection . GetResourceTypes ( ) ;
61- Expression rootCondition = lambdaScope . Accessor ;
72+ Expression rootCondition = context . LambdaScope . Accessor ;
6273
6374 foreach ( IReadOnlyEntityType entityType in concreteEntityTypes )
6475 {
@@ -73,14 +84,14 @@ private Expression CreateLambdaBodyInitializerForTypeHierarchy(FieldSelection se
7384 Dictionary < PropertyInfo , PropertySelector > . ValueCollection propertySelectors =
7485 ToPropertySelectors ( fieldSelectors , resourceType , entityType . ClrType , context . EntityModel ) ;
7586
76- MemberBinding [ ] propertyAssignments = propertySelectors . Select ( selector => CreatePropertyAssignment ( selector , lambdaScope , context ) )
87+ MemberBinding [ ] propertyAssignments = propertySelectors . Select ( selector => CreatePropertyAssignment ( selector , context ) )
7788 . Cast < MemberBinding > ( ) . ToArray ( ) ;
7889
7990 NewExpression createInstance = _resourceFactory . CreateNewExpression ( entityType . ClrType ) ;
8091 MemberInitExpression memberInit = Expression . MemberInit ( createInstance , propertyAssignments ) ;
8192 UnaryExpression castToBaseType = Expression . Convert ( memberInit , baseResourceType . ClrType ) ;
8293
83- BinaryExpression typeCheck = CreateRuntimeTypeCheck ( lambdaScope , entityType . ClrType ) ;
94+ BinaryExpression typeCheck = CreateRuntimeTypeCheck ( context . LambdaScope , entityType . ClrType ) ;
8495 rootCondition = Expression . Condition ( typeCheck , castToBaseType , rootCondition ) ;
8596 }
8697 }
@@ -100,18 +111,16 @@ private static BinaryExpression CreateRuntimeTypeCheck(LambdaScope lambdaScope,
100111 return Expression . MakeBinary ( ExpressionType . Equal , getTypeCall , concreteTypeConstant , false , TypeOpEqualityMethod ) ;
101112 }
102113
103- private MemberInitExpression CreateLambdaBodyInitializerForSingleType ( FieldSelection selection , ResourceType resourceType , LambdaScope lambdaScope ,
114+ private MemberInitExpression CreateLambdaBodyInitializerForSingleType ( FieldSelection selection , ResourceType resourceType ,
104115 QueryClauseBuilderContext context )
105116 {
106117 FieldSelectors fieldSelectors = selection . GetOrCreateSelectors ( resourceType ) ;
107118
108119 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 ) ;
113121
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 ) ;
115124 return Expression . MemberInit ( createInstance , propertyAssignments ) ;
116125 }
117126
@@ -182,50 +191,56 @@ private static void IncludeEagerLoads(ResourceType resourceType, Dictionary<Prop
182191 }
183192 }
184193
185- private MemberAssignment CreatePropertyAssignment ( PropertySelector propertySelector , LambdaScope lambdaScope , QueryClauseBuilderContext context )
194+ private MemberAssignment CreatePropertyAssignment ( PropertySelector propertySelector , QueryClauseBuilderContext context )
186195 {
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 ;
189200
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 ) ;
193204
194205 Expression assignmentRightHandSide = propertyAccess ;
195206
196207 if ( propertySelector . NextLayer != null )
197208 {
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 ) ;
200214 }
201215
202216 return Expression . Bind ( propertySelector . Property , assignmentRightHandSide ) ;
203217 }
204218
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 )
207221 {
208222 Type ? collectionElementType = CollectionConverter . Instance . FindCollectionElementType ( selectorPropertyInfo . PropertyType ) ;
209223 Type bodyElementType = collectionElementType ?? selectorPropertyInfo . PropertyType ;
210224
211225 if ( collectionElementType != null )
212226 {
213- return CreateCollectionInitializer ( outerLambdaScope , selectorPropertyInfo , bodyElementType , layer , context ) ;
227+ return CreateCollectionInitializer ( selectorPropertyInfo , bodyElementType , layer , context ) ;
214228 }
215229
216230 if ( layer . Selection == null || layer . Selection . IsEmpty )
217231 {
218232 return propertyAccess ;
219233 }
220234
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 ) ;
223238 }
224239
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 )
227242 {
228- MemberExpression propertyExpression = Expression . Property ( lambdaScope . Accessor , collectionProperty ) ;
243+ MemberExpression propertyExpression = Expression . Property ( context . LambdaScope . Accessor , collectionProperty ) ;
229244
230245 var nestedContext = new QueryableBuilderContext ( propertyExpression , elementType , typeof ( Enumerable ) , context . EntityModel , context . LambdaScopeFactory ,
231246 context . State ) ;
0 commit comments