@@ -1505,41 +1505,56 @@ private Expression GetConditionalMember(Expression expression, MemberInfo member
15051505 /// <exception cref="InvalidOperationException"><c>InvalidOperationException</c>.</exception>
15061506 private Expression VisitTypeAs ( Expression source , Type targetType )
15071507 {
1508- if ( source . GetMemberType ( ) != MemberType . Entity )
1508+ if ( source . GetMemberType ( ) != MemberType . Entity ) {
15091509 throw new NotSupportedException ( Strings . ExAsOperatorSupportsEntityOnly ) ;
1510+ }
15101511
15111512 // Expression is already of requested type.
1512- var visitedSource = Visit ( source ) ;
1513- if ( source . Type == targetType )
1514- return visitedSource ;
1513+ if ( source . Type == targetType ) {
1514+ return Visit ( source ) ;
1515+ }
15151516
15161517 // Call convert to parent type.
1517- if ( targetType . IsAssignableFrom ( source . Type ) )
1518+ if ( targetType . IsAssignableFrom ( source . Type ) ) {
15181519 return Visit ( Expression . Convert ( source , targetType ) ) ;
1520+ }
15191521
15201522 // Cast to subclass or interface.
15211523 using ( state . CreateScope ( ) ) {
1522- var targetTypeInfo = context . Model . Types [ targetType ] ;
1524+ var bareVisitedSource = Visit ( source ) . StripCasts ( ) . StripMarkers ( ) ;
1525+ if ( ! ( bareVisitedSource is IEntityExpression entityExpression ) )
1526+ throw new InvalidOperationException ( Strings . ExAsOperatorSupportsEntityOnly ) ;
1527+
15231528 // Using of state.Parameter[0] is a very weak approach.
15241529 // `as` operator could be applied on expression that has no relation with current parameter
15251530 // thus the later code will fail.
15261531 // We can't easily find real parameter that need replacement.
15271532 // We work around this situation by supporting some known cases.
15281533 // The simplest (and the only at moment) case is a source being chain of MemberExpressions.
1534+ // Some known cases also can be solved by using outer parameter of visited source which is in form of IEntityExpression
1535+
1536+ var strippedSource = source . StripMemberAccessChain ( ) ;
15291537 var currentParameter = state . Parameters [ 0 ] ;
1530- var parameter = ( source . StripMemberAccessChain ( ) as ParameterExpression ) ?? currentParameter ;
1531- var entityExpression = visitedSource . StripCasts ( ) . StripMarkers ( ) as IEntityExpression ;
15321538
1533- if ( entityExpression == null )
1534- throw new InvalidOperationException ( Strings . ExAsOperatorSupportsEntityOnly ) ;
1539+ ParameterExpression parameter ;
1540+ if ( strippedSource is ParameterExpression pExpression ) {
1541+ parameter = pExpression ;
1542+ }
1543+ else if ( bareVisitedSource is ParameterizedExpression pzExpression && pzExpression . OuterParameter != null ) {
1544+ parameter = pzExpression . OuterParameter ;
1545+ }
1546+ else {
1547+ parameter = currentParameter ;
1548+ }
15351549
15361550 // Replace original recordset. New recordset is left join with old recordset
1537- ProjectionExpression originalResultExpression = context . Bindings [ parameter ] ;
1551+ var originalResultExpression = context . Bindings [ parameter ] ;
15381552 var originalQuery = originalResultExpression . ItemProjector . DataSource ;
1539- int offset = originalQuery . Header . Columns . Count ;
1553+ var offset = originalQuery . Header . Columns . Count ;
15401554
15411555 // Join primary index of target type
1542- IndexInfo indexToJoin = targetTypeInfo . Indexes . PrimaryIndex ;
1556+ var targetTypeInfo = context . Model . Types [ targetType ] ;
1557+ var indexToJoin = targetTypeInfo . Indexes . PrimaryIndex ;
15431558 var queryToJoin = indexToJoin . GetQuery ( ) . Alias ( context . GetNextAlias ( ) ) ;
15441559 var keySegment = entityExpression . Key . Mapping . GetItems ( ) ;
15451560 var keyPairs = keySegment
@@ -1555,10 +1570,12 @@ private Expression VisitTypeAs(Expression source, Type targetType)
15551570 context . Bindings . ReplaceBound ( parameter , projectionExpression ) ;
15561571
15571572 // return new EntityExpression
1558- var result = EntityExpression . Create ( context . Model . Types [ targetType ] , offset , false ) ;
1573+ var result = EntityExpression . Create ( targetTypeInfo , offset , false ) ;
15591574 result . IsNullable = true ;
1560- if ( parameter != currentParameter )
1575+ if ( parameter != currentParameter ) {
15611576 result = ( EntityExpression ) result . BindParameter ( parameter , new Dictionary < Expression , Expression > ( ) ) ;
1577+ }
1578+
15621579 return result ;
15631580 }
15641581 }
0 commit comments