{"record":{"id":"915c6c50c7a4ab68","repo":"dotnet/efcore","slug":"executeupdate-or-executedelete-was-called-on-e","errorCode":null,"errorMessage":"'ExecuteUpdate' or 'ExecuteDelete' was called on entity type '{entityType}', but that entity type is not mapped to a table.","messagePattern":"'ExecuteUpdate' or 'ExecuteDelete' was called on entity type '(.+?)', but that entity type is not mapped to a table\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs","lineNumber":45,"sourceCode":"        {\n            case RelationalAnnotationNames.TptMappingStrategy:\n                throw new InvalidOperationException(\n                    RelationalStrings.ExecuteOperationOnTPT(\n                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),\n                        entityType.DisplayName()));\n\n            // Note that we do allow TPC if the target is a leaf type\n            case RelationalAnnotationNames.TpcMappingStrategy when entityType.GetDirectlyDerivedTypes().Any():\n                throw new InvalidOperationException(\n                    RelationalStrings.ExecuteOperationOnTPC(\n                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),\n                        entityType.DisplayName()));\n        }\n\n        // Find the table model that maps to the entity type; there must be exactly one (e.g. no entity splitting).\n        var targetTable = entityType.GetTableMappings().ToList() switch\n        {\n            [] => throw new InvalidOperationException(\n                RelationalStrings.ExecuteUpdateDeleteOnEntityNotMappedToTable(entityType.DisplayName())),\n            [var singleTableMapping] => singleTableMapping.Table,\n            _ => throw new InvalidOperationException(\n                RelationalStrings.ExecuteOperationOnEntitySplitting(\n                    nameof(EntityFrameworkQueryableExtensions.ExecuteDelete), entityType.DisplayName())),\n        };\n        var selectExpression = (SelectExpression)source.QueryExpression;\n\n        // Find the table expression in the SelectExpression that corresponds to the projected entity type.\n        var projectionBindingExpression = (ProjectionBindingExpression)shaper.ValueBufferExpression;\n        var projection = (StructuralTypeProjectionExpression)selectExpression.GetProjection(projectionBindingExpression);\n        var column = projection.BindProperty(shaper.StructuralType.GetProperties().First());\n        var tableExpression = selectExpression.GetTable(column, out var tableIndex);\n\n        // If the projected table expression (the thing to be deleted) isn't a TableExpression (e.g. it's a set operation), we can't\n        // translate to a simple DELETE (which requires a simple target table), and must fall back to rewriting as a subquery.\n        if (tableExpression.UnwrapJoin() is TableExpression unwrappedTableExpression)\n        {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs#L27-L63","documentation":"TranslateExecuteDelete resolves targetTable from entityType.GetTableMappings(); the empty-list arm throws when the entity type has no table mappings at all. Without a backing table there is nothing to DELETE from, so ExecuteDelete/ExecuteUpdate cannot be translated.","triggerScenarios":"context.Set<KeylessView>().ExecuteDelete() where the type is mapped ToView (not a table) or not mapped at all; ExecuteDelete on a query-only / projection-only entity; an entity type that was never configured with ToTable and is not table-mapped by convention.","commonSituations":"Read-only view-backed entities; keyless types; entities used only for results of FromSql/SQL; misconfigured model where ToTable was removed or never set.","solutions":["Map the entity to a table: modelBuilder.Entity<T>().ToTable(\"t\").","If the type is genuinely view-backed/read-only, do not call ExecuteDelete on it; perform deletes on the writable owner or via raw SQL.","Verify the entity has a primary key and is not excluded from the model (IsIgnored/HasNoKey)."],"exampleFix":"// before (view-backed, no table mapping)\nawait db.Set<ReadOnlyView>().Where(x => x.Old).ExecuteDeleteAsync();\n// after (map to a table, or delete via raw SQL)\nmodelBuilder.Entity<ReadOnlyView>().ToTable(\"readonly_table\");\nawait db.Database.ExecuteSqlRawAsync(\"DELETE FROM readonly_table WHERE old = 1\");","handlingStrategy":"validation","validationCode":"// Ensure the entity is mapped to at least one table before ExecuteDelete/ExecuteUpdate.\nvar et = db.Model.FindEntityType(typeof(TEntity))!;\nif (!et.GetTableMappings().Any())\n    throw new InvalidOperationException(\n        $\"{et.Name} is not mapped to a table; configure ToTable or delete via raw SQL.\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Map every entity that supports bulk delete to a real table (not just ToView).","Audit HasNoKey/ToView-only types before adding ExecuteDelete calls.","Keep an integration test that asserts each bulk-delete target has a table mapping."],"tags":["efcore","executedelete","table-mapping","keyless","model-configuration"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}