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.

HanaBulkCopy has no native async API. By default, the library’s async bulk operations (BulkInsertAsync, BulkMergeAsync, BulkUpdateAsync, BulkDeleteAsync, BulkDeleteByKeyAsync) offload the real HanaBulkCopy load onto a background thread via Task.Run (SapHanaWriteToServerExecution.AsyncOverSync). This class is only used by them when SapHanaBulkDbSetting’s WriteToServerExecution is explicitly set to SapHanaCommandBatcher — a compatibility fallback that pays one INSERT round trip per row and is dramatically slower for any non-trivial row count. The sync operations always use HanaBulkCopy directly. 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);
}

BatchSize and Transaction behave the same way as their equivalents on the other providers’ bulk-write primitives (e.g. FirebirdCommandBatcher) — only the write mechanism (a prepared HanaCommand re-executed per row instead of a single array-bound or bulk-copy call) differs. Each mapping’s destination column can bind with an explicit HanaDbType via SapHanaBulkInsertMapItem, the same mapping type HanaBulkCopy usage in this package binds against — though this is rarely needed since a decimal column’s type is already resolved through TableName.