dotnet/efcore · error · InvalidOperationException
'ExecuteUpdate' is being used over a LINQ operator which isn
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 when ExecuteUpdate is called over a query whose projection yields a complex type instead of an entity type. The translator needs an entity type (with a primary key) to generate the INNER JOIN that wires the bulk update back to the target table; a complex type has no PK and cannot be joined, so the translation aborts. This is tracked under issue #36336 (TODO in source).
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 3a2006ef56)
Solutions
- Rewrite the query so ExecuteUpdate operates over the owning entity type and reach into the complex property via the entity (e.g. context.Set<Root>().ExecuteUpdate(s => s.SetProperty(r => r.Address.City, ...))).
- If you genuinely need to update only complex-type columns, keep the entity as the query root and reference complex members through it so the shaper stays an IEntityType.
- Avoid projecting the complex type out of the query with Select before calling ExecuteUpdate.
Example fix
// before
await ctx.Set<Root>()
.Select(r => r.Address)
.ExecuteUpdateAsync(s => s.SetProperty(a => a.City, "x"));
// after
await ctx.Set<Root>()
.ExecuteUpdateAsync(s => s.SetProperty(r => r.Address.City, "x")); Defensive patterns
Strategy: validation
Validate before calling
// Before ExecuteUpdate, ensure the query projects an entity, not a complex type. Expression<Func<IQueryable<Root>>> rootQuery = () => ctx.Set<Root>(); // Build the query from a DbSet<TRoot> and reference complex members through the root. IQueryable<Root> query = ctx.Set<Root>(); // entity shaper guaranteed await query.ExecuteUpdateAsync(s => s.SetProperty(r => r.Address.City, "x"));
Prevention
- Always root ExecuteUpdate at a DbSet<TEntity> rather than a Select of a complex property.
- Reference complex-type members through the owning entity in the SetProperty lambda.
- Add an integration test asserting ExecuteUpdate works after switching owned -> complex types.
When it happens
Trigger: Calling ExecuteUpdate/ExecuteUpdateAsync on a query that projects out a complex type (e.g. context.Set<Root>().Select(r => r.Address).ExecuteUpdate(s => s.SetProperty(a => a.City, ...))) where Address is a complex type. Also occurs in complex-table-splitting or complex-JSON bulk update tests where the selector unwraps to a StructuralTypeShaperExpression whose StructuralType is IComplexType rather than IEntityType.
Common situations: Migrating from owned types to complex types and keeping ExecuteUpdate calls unchanged; projecting the complex property directly instead of the owning entity; using complex-JSON mappings that surface the complex type as the shaper.
Related errors
- 'ExecuteUpdate' is being used over type '{structuralType}' w
- The complex types '{complexType1}' and '{complexType2}' are
- ExecuteUpdate over JSON columns is not supported when the co
- The following lambda argument to 'SetProperty' does not repr
- The operation '{operation}' cannot be performed on keyless e
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/87a8df59cc837cb6.
Report an issue: GitHub.