dotnet/efcore · error · InvalidOperationException
ExecuteUpdateSubqueryNotSupportedOverComplexTypes
ExecuteUpdateSubqueryNotSupportedOverComplexTypes
Error message
'ExecuteUpdate' is being used over a LINQ operator which isn't natively supported by the database; this cannot be translated because complex type '{complexType}' is projected out. Rewrite your query to project out the containing entity type instead. What it means
Thrown on the ExecuteUpdate pushdown path when the shaper resolved from the property selector binds to a complex type (StructuralType is IComplexType) rather than an entity type. The pushdown rewrites the query via an INNER JOIN on the primary key, but complex types have no primary key, so the rewrite cannot be performed. The message advises projecting the containing entity instead.
Source
Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs:92
// the first property selector.
// The following mechanism for extracting the entity type from property selectors only supports simple member access,
// EF.Function, etc. We also unwrap casts to interface/base class (#29618). Note that owned IncludeExpressions have already
// been pruned from the source before remapping the lambda (#28727).
var firstPropertySelector = setters[0].PropertySelector;
if (!IsMemberAccess(
RemapLambdaBody(source, firstPropertySelector).UnwrapTypeConversion(out _),
RelationalDependencies.Model,
out var baseExpression)
|| _sqlTranslator.TranslateProjection(baseExpression) is not StructuralTypeShaperExpression shaper)
{
throw new InvalidOperationException(RelationalStrings.InvalidPropertyInSetProperty(firstPropertySelector));
}
// TODO: #36336
if (shaper.StructuralType is not IEntityType entityType)
{
throw new InvalidOperationException(
RelationalStrings.ExecuteUpdateSubqueryNotSupportedOverComplexTypes(shaper.StructuralType.DisplayName()));
}
if (entityType.FindPrimaryKey() is not { } pk)
{
throw new InvalidOperationException(
RelationalStrings.ExecuteOperationOnKeylessEntityTypeWithUnsupportedOperator(
nameof(EntityFrameworkQueryableExtensions.ExecuteUpdate),
entityType.DisplayName()));
}
// Generate the INNER JOIN around the original query, on the PK properties.
var outer = (ShapedQueryExpression)Visit(new EntityQueryRootExpression(entityType));
var inner = source;
var outerParameter = Expression.Parameter(entityType.ClrType);
var outerKeySelector = Expression.Lambda(outerParameter.CreateKeyValuesExpression(pk.Properties), outerParameter);
var firstPropertyLambdaExpression = setters[0].PropertySelector;
var entitySource = GetEntitySource(RelationalDependencies.Model, firstPropertyLambdaExpression.Body);View on GitHub (pinned to dbf9771522)
Solutions
- Rewrite the query to project the containing entity type instead of the complex type: SetProperty over the entity parameter and its scalar sub-properties.
- Remove the non-translatable LINQ operator before ExecuteUpdate so the native path is used (no pushdown).
- Set individual scalar properties of the complex type rather than the whole complex object.
- Load and update entities via SaveChanges if the complex-type assignment is essential.
Example fix
// before - complex type projected + non-translatable operator
await db.Orders
.Where(o => o.Tags.Contains("x"))
.Distinct()
.ExecuteUpdateAsync(s => s.SetProperty(o => o.Address, o => new Address { City = "X" }));
// after - project the entity, set scalar sub-properties, drop the unsupported operator
await db.Orders
.Where(o => o.Tags.Contains("x"))
.ExecuteUpdateAsync(s => s.SetProperty(o => o.Address.City, "X")); Defensive patterns
Strategy: validation
Validate before calling
// Detect complex-type projection in a setter selector
static bool TargetsComplexType(LambdaExpression selector, IModel model)
{
if (selector.Body is MemberExpression me)
{
var et = model.FindEntityType(me.Expression?.Type);
if (et?.FindComplexProperty(me.Member.Name) is not null) return true;
}
return false;
}
if (TargetsComplexType(setters[0].PropertySelector, db.Model))
throw new InvalidOperationException("Project the containing entity; set scalar sub-properties of the complex type."); Try / catch
try { await query.ExecuteUpdateAsync(setters); }
catch (InvalidOperationException ex) when (ex.Message.Contains("complex type"))
{
// rewrite setters to target scalar sub-properties of the entity, then retry
await query.ExecuteUpdateAsync(s => s.SetProperty(e => EF.Property<string>(e.Address, "City"), "X"));
} Prevention
- Project the containing entity in ExecuteUpdate; set complex-type sub-properties individually.
- Remove non-translatable operators (Distinct, GroupBy, joins) before ExecuteUpdate to avoid the pushdown path.
- Avoid assigning whole complex-type instances in SetProperty.
- Use SaveChanges when whole-complex-type assignment is required.
When it happens
Trigger: Calling ExecuteUpdate where a SetProperty lambda projects out a complex type directly (e.g. SetProperty(c => c.Address, ...) where Address is a ComplexProperty) combined with a LINQ operator the provider cannot natively translate, forcing the pushdown path.
Common situations: Adopting complex types (ComplexProperty) and using ExecuteUpdate with a non-translatable operator (GroupBy, join, distinct) before it; trying to bulk-assign a whole complex type value.
Related errors
- ExecuteOperationOnOwnedJsonIsNotSupported
- InvalidPropertyInSetProperty
- ExecuteOperationOnTPT
- ExecuteOperationOnTPC
- ExecuteUpdateDeleteOnEntityNotMappedToTable
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/d05de8024942868a.
Report an issue: GitHub.