Releases for RepoDb.SapHana.BulkOperations
View the NuGet package here or download it directly here.
RepoDb.SapHana.BulkOperations (v0.0.1-alpha) - Preview
Released: TBA
New
First release of the bulk operations extension for RepoDb.SapHana.
Verification status: implemented and reviewed, but not yet exercised against a live SAP HANA instance. Verify the pseudo-table lifecycle, the concurrency caveat below, and the identity-assignment arithmetic end-to-end before relying on this package in production.
Architectural note: SAP HANA has no native bulk-load API to build on, and its SQL parser rejects a multi-row
INSERT ... VALUES (...), (...)list. Every write here is a client-buffered loop of single-row, parameterizedINSERTstatements — one round trip per row — against the real or pseudo table.
What’s included
- BulkInsert, BulkMerge, BulkUpdate, BulkDelete and BulkDeleteByKey, each with an
Asyncoverload, callable against aHanaConnectionwith an entity list, aDataTable, or anIDataReader(BulkDeleteByKeytakes a target table name and a list of primary key values directly, rather than an entity type parameter). - A row-by-row write pipeline (an internal
ColumnFilteredDataReaderplus a bufferedINSERTloop) that buffers rows client-side (batchSize, default500) to control memory/flush frequency.bulkCopyTimeoutapplies here as each row’sCommandTimeout. SapHanaBulkImportIdentityBehavior(KeepIdentitydefault,ReturnIdentity) — controls whether identity values are sent as-is or read back.ReturnIdentitypre-assigns identities client-side (MAX(identity) + 1, offset by the pseudo table’s own row-order column) before moving rows into the real table with a singleINSERT ... SELECT, then reads them back ordered by that same row-order column.SapHanaBulkImportPseudoTableType(Auto,Memory,Physical) — selects the staging-table strategy backing every operation.- SapHanaBulkInsertMapItem — explicit source-to-destination column mapping, with an optional
HanaDbTypeoverride. Explicit mappings are also type-checked up front: an incompatible source/destination CLR type pairing (other than the allowedGuid↔stringand integral-to-integral widenings) throws anInvalidTypeExceptionimmediately, rather than failing inside SAP HANA. - SapHanaTraceKeys — the tracing key constants for the five bulk operations, for use with ITrace.
SapHanaGuidToStringPropertyHandler— maps aGuidentity property to/from anNVARCHAR(36)column, since SAP HANA has no native GUID type. Ships in this package (not the coreRepoDb.SapHanaprovider), but is a plainIPropertyHandler<string, Guid>usable with any operation, not just the bulk ones.BulkMergeuses a real, single-statement ANSIMERGEwhenidentityBehaviorisKeepIdentity. WhenReturnIdentityis requested, a three-step sequence runs instead: (1) copy the existing identity value onto every pseudo row that already matches a target row, (2) assign a fresh, gap-free identity — via a correlatedCOUNT(*), deliberately plain portable ANSI SQL rather than a window function — to every unmatched row, then (3) run theMERGEwith the identity column inserted explicitly. See BulkMerge for details.BulkUpdate/the update half ofBulkMergeuses a correlated-subquerySET (col1, col2, ...) = (SELECT ...)form guarded byWHERE EXISTS, since SAP HANA has no multi-tableUPDATE ... JOIN.- Dropping a pseudo table swallows SAP HANA’s “invalid table name” native error (
259) — HANA’sDROP TABLEhas noIF EXISTSclause, so a drop against a pseudo table that was never created (or already dropped) is expected to fail this specific way, and only this way.
Known limitations (v1)
- Pseudo table names are deterministic, not per-call-unique — built from the target table name, the operation, and the
pseudoTableType(e.g.PhysicalPersonMerge). Combined with the next limitation, this means two concurrent bulk calls of the same operation against the same table can genuinely interfere with each other’s staged rows. AutoandMemoryboth currently resolve toPhysicalat runtime — the internal resolution logic returnsPhysicalon every outcome, so the session-isolatedLOCAL TEMPORARYpathMemoryadvertises is not implemented yet. Avoid running concurrent SAP HANA bulk operations of the same kind against the same table until this is resolved.- Every “bulk” write is really a client-buffered loop of single-row
INSERTstatements — one round trip per row.batchSize(default500) only controls how many rows are buffered between flushes; it does not reduce round trips. BulkInsert/BulkMerge’sReturnIdentityidentity pre-assignment reads the liveMAX(identity)off the table’s own row data (not a cached sequence counter), which can never be stale but does leave a small race window against a concurrent writer to the same table between that read and the finalINSERT/MERGE.- Per the library’s own source comments,
BulkMerge’s correlated-COUNTrank computation for assigning fresh identities to unmatched rows in theReturnIdentitypath is the least-verified statement in the whole provider. Verify it specifically, especially under concurrent writers, before relying on it in production. - The
DbDataReaderoverloads ofBulkInsertandBulkMergehave noidentityBehaviorargument — a forward-only, single-pass reader cannot be rewound to correlate generated identity values back onto a source row. BulkDeleteByKeytakes atableNamestring directly (BulkDeleteByKey<TPrimaryKey>(connection, tableName, primaryKeys, ...)) rather than an entity type parameter.This package inherits every Known limitation of RepoDb.SapHana itself (e.g. no table hints,
Mergerequiring a known primary key value up front).- Referenced the
RepoDbpackagev1.16.0. - Referenced the
RepoDb.SapHanapackagev0.0.1-alpha. - Referenced the
Sap.Data.Hana.Net.v6.0packagev2.29.25.