SapHanaCommandBatcher
A HanaCommand-based row-by-row batch-insert class for SAP HANA, offering true asynchronous execution where HanaBulkCopy has none.
This class writes rows to a SAP HANA table by executing a prepared INSERT INTO ... VALUES (:p0, :p1, ...) HanaCommand once per row, following the same conventions (DestinationTableName, BatchSize, Transaction, ColumnMappings) as HanaBulkCopy.
It is part of RepoDb.SapHana.BulkOperations and implements IDisposable.
HanaBulkCopyhas no native async API. By default, the library’s async bulk operations (BulkInsertAsync,BulkMergeAsync,BulkUpdateAsync,BulkDeleteAsync,BulkDeleteByKeyAsync) offload the realHanaBulkCopyload onto a background thread viaTask.Run(SapHanaWriteToServerExecution.AsyncOverSync). This class is only used by them when SapHanaBulkDbSetting’sWriteToServerExecutionis explicitly set toSapHanaCommandBatcher— a compatibility fallback that pays oneINSERTround trip per row and is dramatically slower for any non-trivial row count. The sync operations always useHanaBulkCopydirectly. Using this class directly is otherwise only necessary for a custom bulk-write path outside of those operations.
Properties
| Name | Description |
|---|---|
| DestinationTableName | The target table name, already quoted as HanaBulkCopy.DestinationTableName would expect. |
| TableName | The target table name, unquoted, used to look up each destination column’s actual type so its parameter’s HanaDbType can be pre-declared — see the remarks on AddParameters for why this is required for decimal columns. |
| BulkCopyTimeout | The command timeout, in seconds. Zero uses the provider default. |
| BatchSize | The number of rows executed against a single prepared HanaCommand before it is disposed and a fresh one is prepared. Zero (the default) reuses one command for every row. |
| Transaction | The HanaTransaction each row is executed under. |
| ColumnMappings | A SapHanaCommandBatcherColumnMappingCollection of explicit source-to-destination column mappings. When left empty, columns are mapped by name. |
Create a new Instance
using (var connection = new HanaConnection(connectionString))
{
connection.Open();
using var batcher = new SapHanaCommandBatcher(connection)
{
DestinationTableName = "\"Person\"",
TableName = "Person",
BatchSize = 1000
};
}
Usability
Call WriteToServer()/WriteToServerAsync() with either an IDataReader or a DataRow[] to write rows. Both overloads return the number of rows written.
Via an IDataReader (e.g. DataEntityDataReader):
using (var connection = new HanaConnection(connectionString))
{
connection.Open();
var people = GetPeople(100000);
using var reader = new DataEntityDataReader<Person>(people);
using var batcher = new SapHanaCommandBatcher(connection)
{
DestinationTableName = "\"Person\"",
TableName = "Person"
};
var writtenRows = await batcher.WriteToServerAsync(reader);
}
Via a DataRow[]:
using (var connection = new HanaConnection(connectionString))
{
connection.Open();
var rows = GetPeopleAsDataTable().Select();
using var batcher = new SapHanaCommandBatcher(connection)
{
DestinationTableName = "\"Person\"",
TableName = "Person"
};
var writtenRows = await batcher.WriteToServerAsync(rows);
}
With explicit column mappings:
using (var connection = new HanaConnection(connectionString))
{
connection.Open();
using var batcher = new SapHanaCommandBatcher(connection)
{
DestinationTableName = "\"Person\"",
TableName = "Person"
};
batcher.ColumnMappings.Add("FirstName", "FName");
batcher.ColumnMappings.Add("LastName", "LName");
var people = GetPeople(100000);
using var reader = new DataEntityDataReader<Person>(people);
var writtenRows = await batcher.WriteToServerAsync(reader);
}
BatchSizeandTransactionbehave the same way as their equivalents on the other providers’ bulk-write primitives (e.g. FirebirdCommandBatcher) — only the write mechanism (a preparedHanaCommandre-executed per row instead of a single array-bound or bulk-copy call) differs. Each mapping’s destination column can bind with an explicitHanaDbTypevia SapHanaBulkInsertMapItem, the same mapping typeHanaBulkCopyusage in this package binds against — though this is rarely needed since adecimalcolumn’s type is already resolved throughTableName.