{"record":{"id":"cb1878f5861b7a6a","repo":"dotnet/efcore","slug":"the-data-deletion-operation-on-table-is-not-as","errorCode":null,"errorMessage":"The data deletion operation on '{table}' is not associated with a model. Either add a model to the migration, or specify the column types in all data operations.","messagePattern":"The data deletion operation on '(.+?)' is not associated with a model\\. Either add a model to the migration, or specify the column types in all data operations\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs","lineNumber":985,"sourceCode":"        if (operation.KeyColumns.Length != operation.KeyValues.GetLength(1))\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.DeleteDataOperationValuesCountMismatch(\n                    operation.KeyValues.GetLength(1), operation.KeyColumns.Length, FormatTable(operation.Table, operation.Schema)));\n        }\n\n        if (operation.KeyColumnTypes != null\n            && operation.KeyColumns.Length != operation.KeyColumnTypes.Length)\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.DeleteDataOperationTypesCountMismatch(\n                    operation.KeyColumnTypes.Length, operation.KeyColumns.Length, FormatTable(operation.Table, operation.Schema)));\n        }\n\n        if (operation.KeyColumnTypes == null\n            && model == null)\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.DeleteDataOperationNoModel(\n                    FormatTable(operation.Table, operation.Schema)));\n        }\n\n        var keyPropertyMappings = operation.KeyColumnTypes == null\n            ? GetPropertyMappings(operation.KeyColumns, operation.Table, operation.Schema, model)\n            : null;\n\n        for (var i = 0; i < operation.KeyValues.GetLength(0); i++)\n        {\n            var modificationCommand = Dependencies.ModificationCommandFactory.CreateNonTrackedModificationCommand(\n                new NonTrackedModificationCommandParameters(operation.Table, operation.Schema, SensitiveLoggingEnabled));\n            modificationCommand.EntityState = EntityState.Deleted;\n\n            for (var j = 0; j < operation.KeyColumns.Length; j++)\n            {\n                var name = operation.KeyColumns[j];\n                var value = operation.KeyValues[i, j];","sourceCodeStart":967,"sourceCodeEnd":1003,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs#L967-L1003","documentation":"Thrown inside GenerateModificationCommands(DeleteDataOperation, ...) in src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs:985 (message key DeleteDataOperationNoModel). EF needs a type mapping for each key column to build the WHERE clause. It gets this from the model (entity mapped to the table) or from explicit KeyColumnTypes. When both are absent (KeyColumnTypes == null && model == null) it throws InvalidOperationException.","triggerScenarios":"Calling migrationBuilder.DeleteData on a table not mapped to any entity, in a model-less migration, without supplying keyColumnTypes:. Also when migrations are applied through a code path that passes model == null into the generator while the migration contains DeleteData.","commonSituations":"Standalone migrations assemblies with hand-authored DeleteData for unmapped tables. Removing an entity type from the model while its DeleteData migration remains. Running migrations via a custom host that does not supply the model.","solutions":["Supply keyColumnTypes: on the DeleteData call so EF can build key type mappings without a model.","Map the table to an entity type (modelBuilder.Entity<T>().ToTable(\"...\")) and ensure the migration runs with that model attached.","Use HasData and let EF scaffold the corresponding DeleteData with the model.","Register the migrations assembly with a provider that supplies the runtime model."],"exampleFix":"// before (no model, no key types):\nmigrationBuilder.DeleteData(\n    table: \"Lookups\",\n    keyColumns: new[] { \"Code\" },\n    keyValues: new object[,] { { \"A\" } });\n\n// after (supply key types when there is no model):\nmigrationBuilder.DeleteData(\n    table: \"Lookups\",\n    keyColumns: new[] { \"Code\" },\n    keyColumnTypes: new[] { \"nvarchar(16)\" },\n    keyValues: new object[,] { { \"A\" } });","handlingStrategy":"validation","validationCode":"static bool DeleteDataHasTypeSource(string[]? keyColumnTypes, IModel? model)\n{\n    return keyColumnTypes != null || model != null;\n}\n\n// usage: if no model is attached, you MUST pass keyColumnTypes\nif (!DeleteDataHasTypeSource(keyColumnTypes, targetModel))\n    throw new InvalidOperationException(\"DeleteData needs a model or explicit keyColumnTypes.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    await dbContext.Database.MigrateAsync();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"not associated with a model\") && ex.Message.Contains(\"data deletion\"))\n{\n    logger.LogError(ex, \"DeleteData on an unmapped table needs explicit keyColumnTypes or a model.\");\n    throw;\n}","preventionTips":["Map every seeded table to an entity type so the model provides key type mappings.","For model-less migrations, always pass keyColumnTypes for every DeleteData key column.","Run migrations with the runtime model attached.","Drive seed data through HasData so it stays bound to the model."],"tags":["migrations","data-seeding","delete-data","type-mapping","invalidoperation"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}