Thanks to @SoftStoneDevelop who posted the original issue; I've moved the original proposal to the bottom - it's very similar.
The DbBatch abstraction was added to System.Data in .NET 6.0 (issue). In a nutshell, it allows sending multiple SQL statements to the database in a single roundtrip through the use of multiple DbBatchCommands, each representing a statement. This is superior in various ways to the classical way of implementing batching in ADO.NET, which is to insert multiple semicolon-separated SQL statements into DbCommand.CommandText.
Unfortunately, due to an oversight, an API is missing on this abstraction for creating a a DbParameters, which are needed for parameterizing SQL.
SqlParameter
), but database-agnostic code which doesn't target a specific database provider requires factory methods to construct System.Data objects.DbConnection
directly, and does not have access to the driver's DbProviderFactory
. This is notably the case for the popular Dapper micro-ORM (which is the main motivation behind this proposal).DbCommand
also exposes a CreateParameter() factory method, allowing anyone with a connection (or even just a command) to create parameters.DbBatch
nor its contains DbBatchCommand
expose a similar method.class DbBatchCommand { public virtual DbParameter CreateParameter() => throw new NotSupportedException(); public virtual bool CanCreateParameter => false; }Notes
CreateParameter
method to DbBatchCommand
, not to DbBatch
; the former is where the parameters actually live, and is the analog of DbCommand
in that sense. It's also conceivable that a single DbBatchCommand
be passed around, and that a method accepting it would want to add parameters to it.DbBatchCommand
implementations. Instead, the proposal adds a method which throws by default; all providers implementing DbBatch
will be expected to override it.DbBatchCommand
doesn't reference DbConnection
or similar, so there's no way to provide a default implementation which would access the CreateParameter()
method e.g. on DbCommand
. If this API were placed on DbBatch
, it could access the DbConnection
instance for that batch, create a command and call its CreateProvider
method; however, this would have been of limited value since DbBatch
can exist without an assigned connection, at which point this API would have to throw anyway. So it seems preferable to have the new API on DbBatchCommand
where it belongs.CanCreateParameter
can be used to discover whether calling CreateParameter
will throw or not; providers are expected to override it to return true when implementing CreateParameter
. While it's not expected that programs can continue in a useful way if they require CreateParameter()
and it isn't supported, at the very least this would allow the consuming program to throw a meaningful exception.CanCreateParameter
is consistent with other CanCreate*
capability properties in System.Data, specifically in DbProviderFactory (e.g. CanCreateBatch
, CanCreateDataAdapter
...).DbBatch
(Npgsql and MySqlConnector).It is not possible to create a parameter for a DbBatchCommand without knowing the specific parameter of a specific provider (for example, NpgsqlParameter
). This makes it difficult to use Batch abstracted from the provider.
With the non batch query, we are all right:
public void Method(DbConnection connection) { DbCommand command = connection.CreateCommand(); DbParameter commandParametr = command.CreateParameter(); //... command.Parameters.Add(commandParametr); //... }API Proposal
public abstract class DbBatchCommand { public abstract string CommandText { get; set; } public abstract CommandType CommandType { get; set; } public abstract int RecordsAffected { get; } public DbParameterCollection Parameters => DbParameterCollection; protected abstract DbParameterCollection DbParameterCollection { get; } public abstract DbParameter CreateParameter(); }API Usage
public void Method(DbConnection connection) { DbBatch batch = connection.CreateBatch(); DbBatchCommand batchCommand = batch.CreateBatchCommand(); //set batchCommand properties //... DbParametr batchParametr = batchCommand.CreateParameter();//!New Method! //set batchParametr properties //... batchCommand.Parameters.Add(batchParametr); batch.BatchCommands.Add(batchCommand); //execute batch //... }
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4