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

  1. 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, ...))).
  2. 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.
  3. 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

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


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/87a8df59cc837cb6. Report an issue: GitHub.