{"record":{"id":"2470b014015e30a9","repo":"dotnet/efcore","slug":"the-number-of-key-column-types-typescount-does","errorCode":null,"errorMessage":"The number of key column types ({typesCount}) doesn't match the number of key columns ({columnsCount}) for the data deletion operation on '{table}'. Provide the same number of key column types and key columns.","messagePattern":"The number of key column types \\((.+?)\\) doesn't match the number of key columns \\((.+?)\\) for the data deletion operation on '(.+?)'\\. Provide the same number of key column types and key columns\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs","lineNumber":977,"sourceCode":"    /// </summary>\n    /// <param name=\"operation\">The data operation to generate commands for.</param>\n    /// <param name=\"model\">The model.</param>\n    /// <returns>The commands that correspond to the given operation.</returns>\n    protected virtual IEnumerable<IReadOnlyModificationCommand> GenerateModificationCommands(\n        DeleteDataOperation operation,\n        IModel? model)\n    {\n        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        {","sourceCodeStart":959,"sourceCodeEnd":995,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs#L959-L995","documentation":"Thrown when generating SQL for a DeleteData migration operation where the user supplied KeyColumnTypes but its length differs from KeyColumns. EF needs every key column to have a matching declared store type so it can resolve a type mapping for the parameterized delete.","triggerScenarios":"Calling migrationBuilder.DeleteData(...) with a keyColumnTypes: array whose element count differs from keyColumns:. Generated when MigrationsSqlGenerator.GenerateModificationCommands(DeleteDataOperation) runs and operation.KeyColumnTypes != null && operation.KeyColumns.Length != operation.KeyColumnTypes.Length.","commonSituations":"Hand-edited migration where a column was added/removed from keyColumns but keyColumnTypes was not updated. Migrations written for providers that require explicit types (e.g. SQLite) where a composite key column was missed.","solutions":["Make the keyColumnTypes array length equal to the keyColumns array length, one store type string per key column.","If you do not need explicit types, remove keyColumnTypes entirely and rely on the model to resolve mappings.","Regenerate the migration with Add-Migration / dotnet ef migrations add so the scaffolder writes consistent arrays."],"exampleFix":"// before\nmigrationBuilder.DeleteData(\n    table: \"Users\",\n    keyColumns: new[] { \"TenantId\", \"Id\" },\n    keyValues: new object[,] { { 1, 10 } },\n    keyColumnTypes: new[] { \"int\" }); // length 1 != 2\n\n// after\nmigrationBuilder.DeleteData(\n    table: \"Users\",\n    keyColumns: new[] { \"TenantId\", \"Id\" },\n    keyValues: new object[,] { { 1, 10 } },\n    keyColumnTypes: new[] { \"int\", \"int\" });","handlingStrategy":"validation","validationCode":"void ValidateDeleteData(string table, string[] keyColumns, string[]? keyColumnTypes, object[,] keyValues)\n{\n    if (keyColumnTypes is not null && keyColumnTypes.Length != keyColumns.Length)\n        throw new ArgumentException($\"{table}: keyColumnTypes({keyColumnTypes.Length}) != keyColumns({keyColumns.Length})\");\n    if (keyValues.GetLength(1) != keyColumns.Length)\n        throw new ArgumentException($\"{table}: keyValues dim1 != keyColumns\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always build keyColumnTypes and keyColumns from the same source list so lengths stay in sync.","Prefer omitting keyColumnTypes and letting the model resolve types.","Add a unit test that asserts every DeleteData operation in a migration has matching array lengths."],"tags":["ef-core","migrations","deletedata","argument-validation"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}