{"record":{"id":"74a5fecd296ebf42","repo":"tursodatabase/turso","slug":"batch-command-must-be-a-tursobatchcommand","errorCode":null,"errorMessage":"Batch command must be a TursoBatchCommand.","messagePattern":"Batch command must be a TursoBatchCommand\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data/TursoBatchCommandCollection.cs","lineNumber":78,"sourceCode":"    protected override DbBatchCommand GetBatchCommand(int index)\n    {\n        return _commands[index];\n    }\n\n    protected override void SetBatchCommand(int index, DbBatchCommand batchCommand)\n    {\n        _commands[index] = RequireTursoBatchCommand(batchCommand);\n    }\n\n    internal IReadOnlyList<TursoBatchCommand> AsReadOnly()\n    {\n        return _commands;\n    }\n\n    private static TursoBatchCommand RequireTursoBatchCommand(DbBatchCommand command)\n    {\n        return command as TursoBatchCommand\n               ?? throw new ArgumentException(\"Batch command must be a TursoBatchCommand.\", nameof(command));\n    }\n}\n","sourceCodeStart":60,"sourceCodeEnd":81,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/dotnet/src/Turso.Data/TursoBatchCommandCollection.cs#L60-L81","documentation":"TursoBatchCommandCollection.RequireTursoBatchCommand validates every DbBatchCommand passed to Add, Insert, or the indexer setter (TursoBatchCommandCollection.cs:70-75). ADO.NET batch collections are provider-specific, so a command object created by another provider (SqlBatchCommand, NpgsqlBatchCommand) or a custom DbBatchCommand subclass is rejected with ArgumentException instead of failing later during execution.","triggerScenarios":"batch.Commands.Add(new SqlBatchCommand(...)); or inserting/assigning any DbBatchCommand that is not a TursoBatchCommand instance into a TursoBatch's Commands collection.","commonSituations":"Provider-agnostic data-access layers written against the abstract DbBatch/DbBatchCommand types; copy-pasted SqlClient batch snippets; resolving the wrong DbProviderFactory from DbProviderFactories so foreign batch commands flow into a TursoBatch.","solutions":["Construct entries directly: batch.Commands.Add(new TursoBatchCommand { CommandText = ... }).","Use TursoFactory (the Turso DbProviderFactory) consistently so connection, batch, and commands all come from the same provider.","Audit generic batch-building helpers and replace mixed-provider objects with ones created by the connection that owns the batch."],"exampleFix":"// before\nvar batch = conn.CreateBatch();\nbatch.Commands.Add(new SqlBatchCommand { CommandText = \"SELECT 1\" }); // throws ArgumentException\n\n// after\nvar batch = conn.CreateBatch();\nbatch.Commands.Add(new TursoBatchCommand { CommandText = \"SELECT 1\" });","handlingStrategy":"type-guard","validationCode":"foreach (var c in commandsToAdd)\n{\n    if (c is not TursoBatchCommand)\n        throw new InvalidOperationException($\"{c.GetType().Name} cannot be added to a TursoBatch.\");\n}","typeGuard":"static bool IsTursoBatchCommand(DbBatchCommand c) => c is TursoBatchCommand;","tryCatchPattern":"try\n{\n    batch.Commands.Add(cmd);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"TursoBatchCommand\"))\n{\n    // Replace the foreign entry with one created for this batch.\n    var tursoCmd = new TursoBatchCommand { CommandText = cmd.CommandText };\n    batch.Commands.Add(tursoCmd);\n}","preventionTips":["Build every batch entry with new TursoBatchCommand() so the concrete type always matches.","Source connection, batch, and commands from one DbProviderFactory (TursoFactory).","Never mix provider objects inside a single DbBatchCommandCollection."],"tags":["dotnet","ado-net","tursodb","batch","type-mismatch"],"backgroundTag":"ado-net-provider-type-mismatch","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}