dotnet/efcore · error · InvalidOperationException

The operation '{operation}' cannot be performed on keyless e

Error message

The operation '{operation}' cannot be performed on keyless entity type '{entityType}', since it contains an operator not natively supported by the database provider.

What it means

Thrown when ExecuteUpdate (or ExecuteDelete) targets a keyless entity type. Bulk update/delete generates an INNER JOIN on the entity's primary key columns; a keyless entity has no PK, so the join cannot be constructed and the operation is rejected with the 'operator not natively supported' framing.

Source

Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs:98

            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);
            var innerKeySelector = Expression.Lambda(
                entitySource.CreateKeyValuesExpression(pk.Properties), firstPropertyLambdaExpression.Parameters);

            var joinPredicate = CreateJoinPredicate(outer, outerKeySelector, inner, innerKeySelector);

            Check.DebugAssert(joinPredicate != null, "Join predicate shouldn't be null");

View on GitHub (pinned to 3a2006ef56)

Solutions

  1. Add a primary key to the entity type via HasKey(...) / Key(...) so ExecuteUpdate can join back to the table.
  2. If the type is genuinely keyless and read-only, do not call ExecuteUpdate/ExecuteDelete on it; load, mutate, and SaveChanges on a keyed entity instead.
  3. Switch the bulk operation to run against a keyed entity type that maps to the same table.

Example fix

// before
modelBuilder.Entity<EagleQuery>().HasNoKey();
await ctx.Set<EagleQuery>().ExecuteUpdateAsync(s => s.SetProperty(e => e.Name, "x"));
// after
modelBuilder.Entity<Eagle>().HasKey(e => e.Id);
await ctx.Set<Eagle>().ExecuteUpdateAsync(s => s.SetProperty(e => e.Name, "x"));
Defensive patterns

Strategy: validation

Validate before calling

// Verify the entity has a primary key before calling ExecuteUpdate/ExecuteDelete.
IEntityType? et = ctx.Model.FindEntityType(typeof(EagleQuery));
if (et?.FindPrimaryKey() is null)
{
    throw new InvalidOperationException($"{et?.DisplayName()} is keyless; bulk update not supported.");
}
await ctx.Set<EagleQuery>().ExecuteUpdateAsync(s => s.SetProperty(e => e.Name, "x"));

Try / catch

try { await query.ExecuteUpdateAsync(setters); }
catch (InvalidOperationException ex) when (ex.Message.Contains("keyless entity type"))
{
    logger.LogWarning("Bulk update on keyless entity is not supported: {Msg}", ex.Message);
    // fall back to load + SaveChanges on a keyed entity
}

Prevention

When it happens

Trigger: Defining an entity type with HasNoKey() and then calling ExecuteUpdate/ExecuteDelete on a query rooted at it, or on a query (e.g. a view or TVF) that resolves to a keyless entity. The source region shows the check `entityType.FindPrimaryKey() is not { } pk` failing for ExecuteUpdate; the same helper fires for ExecuteDelete in the sibling file.

Common situations: Mapping database views, raw SQL results, or query results as keyless entities and attempting bulk modifications; forgetting that a HasNoKey entity cannot participate in write operations.

Related errors


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