@@ -1044,7 +1044,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
10441044 {
10451045 if ( source . ShaperExpression is IncludeExpression includeExpression )
10461046 {
1047- source = source . UpdateShaperExpression ( PruneOwnedIncludes ( includeExpression ) ) ;
1047+ source = source . UpdateShaperExpression ( PruneIncludes ( includeExpression ) ) ;
10481048 }
10491049
10501050 if ( source . ShaperExpression is not EntityShaperExpression entityShaperExpression )
@@ -1143,20 +1143,6 @@ static bool AreOtherNonOwnedEntityTypesInTheTable(IEntityType rootType, ITableBa
11431143 Expression . Quote ( Expression . Lambda ( predicateBody , entityParameter ) ) ) ;
11441144
11451145 return TranslateExecuteDelete ( ( ShapedQueryExpression ) Visit ( newSource ) ) ;
1146-
1147- static Expression PruneOwnedIncludes ( IncludeExpression includeExpression )
1148- {
1149- if ( includeExpression . Navigation is ISkipNavigation
1150- || includeExpression . Navigation is not INavigation navigation
1151- || ! navigation . ForeignKey . IsOwnership )
1152- {
1153- return includeExpression ;
1154- }
1155-
1156- return includeExpression . EntityExpression is IncludeExpression innerIncludeExpression
1157- ? PruneOwnedIncludes ( innerIncludeExpression )
1158- : includeExpression . EntityExpression ;
1159- }
11601146 }
11611147
11621148 /// <summary>
@@ -1178,6 +1164,13 @@ static Expression PruneOwnedIncludes(IncludeExpression includeExpression)
11781164 ShapedQueryExpression source ,
11791165 LambdaExpression setPropertyCalls )
11801166 {
1167+ // Our source may have IncludeExpressions because of owned entities or auto-include; unwrap these, as they're meaningless for
1168+ // ExecuteUpdate's lambdas. Note that we don't currently support updates across tables.
1169+ if ( source . ShaperExpression is IncludeExpression includeExpression )
1170+ {
1171+ source = source . UpdateShaperExpression ( PruneIncludes ( includeExpression ) ) ;
1172+ }
1173+
11811174 var propertyValueLambdaExpressions = new List < ( LambdaExpression , Expression ) > ( ) ;
11821175 PopulateSetPropertyCalls ( setPropertyCalls . Body , propertyValueLambdaExpressions , setPropertyCalls . Parameters [ 0 ] ) ;
11831176 if ( TranslationErrorDetails != null )
@@ -1382,11 +1375,16 @@ void PopulateSetPropertyCalls(
13821375 when parameter == p :
13831376 break ;
13841377
1385- case MethodCallExpression methodCallExpression
1386- when methodCallExpression . Method . IsGenericMethod
1387- && methodCallExpression . Method . Name == nameof ( SetPropertyCalls < int > . SetProperty )
1388- && methodCallExpression . Method . DeclaringType ! . IsGenericType
1389- && methodCallExpression . Method . DeclaringType . GetGenericTypeDefinition ( ) == typeof ( SetPropertyCalls < > ) :
1378+ case MethodCallExpression
1379+ {
1380+ Method :
1381+ {
1382+ IsGenericMethod : true ,
1383+ Name : nameof ( SetPropertyCalls < int > . SetProperty ) ,
1384+ DeclaringType . IsGenericType : true
1385+ }
1386+ } methodCallExpression
1387+ when methodCallExpression . Method . DeclaringType . GetGenericTypeDefinition ( ) == typeof ( SetPropertyCalls < > ) :
13901388
13911389 list . Add ( ( ( LambdaExpression ) methodCallExpression . Arguments [ 0 ] , methodCallExpression . Arguments [ 1 ] ) ) ;
13921390
@@ -1401,8 +1399,8 @@ when methodCallExpression.Method.IsGenericMethod
14011399 }
14021400
14031401 // For property setter selectors in ExecuteUpdate, we support only simple member access, EF.Function, etc.
1404- // We also unwrap casts to interface/base class (#29618), as well as IncludeExpressions (which occur when the target entity has
1405- // owned entities, #28727).
1402+ // We also unwrap casts to interface/base class (#29618). Note that owned IncludeExpressions have already been pruned from the
1403+ // source before remapping the lambda ( #28727).
14061404 static bool TryProcessPropertyAccess (
14071405 IModel model ,
14081406 ref Expression expression ,
@@ -1411,7 +1409,7 @@ static bool TryProcessPropertyAccess(
14111409 expression = expression . UnwrapTypeConversion ( out _ ) ;
14121410
14131411 if ( expression is MemberExpression { Expression : not null } memberExpression
1414- && Unwrap ( memberExpression . Expression ) is EntityShaperExpression ese )
1412+ && memberExpression . Expression . UnwrapTypeConversion ( out _ ) is EntityShaperExpression ese )
14151413 {
14161414 expression = memberExpression . Update ( ese ) ;
14171415 entityShaperExpression = ese ;
@@ -1421,7 +1419,7 @@ static bool TryProcessPropertyAccess(
14211419 if ( expression is MethodCallExpression mce )
14221420 {
14231421 if ( mce . TryGetEFPropertyArguments ( out var source , out _ )
1424- && Unwrap ( source ) is EntityShaperExpression ese1 )
1422+ && source . UnwrapTypeConversion ( out _ ) is EntityShaperExpression ese1 )
14251423 {
14261424 if ( source != ese1 )
14271425 {
@@ -1435,7 +1433,7 @@ static bool TryProcessPropertyAccess(
14351433 }
14361434
14371435 if ( mce . TryGetIndexerArguments ( model , out var source2 , out _ )
1438- && Unwrap ( source2 ) is EntityShaperExpression ese2 )
1436+ && source2 . UnwrapTypeConversion ( out _ ) is EntityShaperExpression ese2 )
14391437 {
14401438 expression = mce . Update ( ese2 , mce . Arguments ) ;
14411439 entityShaperExpression = ese2 ;
@@ -1445,18 +1443,6 @@ static bool TryProcessPropertyAccess(
14451443
14461444 entityShaperExpression = null ;
14471445 return false ;
1448-
1449- static Expression Unwrap ( Expression expression )
1450- {
1451- expression = expression . UnwrapTypeConversion ( out _ ) ;
1452-
1453- while ( expression is IncludeExpression includeExpression )
1454- {
1455- expression = includeExpression . EntityExpression ;
1456- }
1457-
1458- return expression ;
1459- }
14601446 }
14611447
14621448 static Expression GetEntitySource ( IModel model , Expression propertyAccessExpression )
@@ -1628,6 +1614,18 @@ private Expression RemapLambdaBody(ShapedQueryExpression shapedQueryExpression,
16281614 private Expression ExpandSharedTypeEntities ( SelectExpression selectExpression , Expression lambdaBody )
16291615 => _sharedTypeEntityExpandingExpressionVisitor . Expand ( selectExpression , lambdaBody ) ;
16301616
1617+ private static Expression PruneIncludes ( IncludeExpression includeExpression )
1618+ {
1619+ if ( includeExpression . Navigation is ISkipNavigation or not INavigation )
1620+ {
1621+ return includeExpression ;
1622+ }
1623+
1624+ return includeExpression . EntityExpression is IncludeExpression innerIncludeExpression
1625+ ? PruneIncludes ( innerIncludeExpression )
1626+ : includeExpression . EntityExpression ;
1627+ }
1628+
16311629 private sealed class SharedTypeEntityExpandingExpressionVisitor : ExpressionVisitor
16321630 {
16331631 private readonly RelationalSqlTranslatingExpressionVisitor _sqlTranslator ;
0 commit comments