Skip to content

Bulk Insert ​

Inserting large volumes of data one row at a time is prohibitively slow for most production workloads. The SmartSql.Bulk package provides a database-agnostic interface for high-performance bulk inserts, with native implementations for SQL Server, MySQL, MySQL (MySqlConnector), and PostgreSQL. Each implementation uses the database's own bulk loading mechanism -- SqlBulkCopy, MySqlBulkLoader, and COPY BINARY respectively -- to achieve maximum throughput.

At a Glance ​

FeatureDescription
PackageSmartSql.Bulk (base)
ImplementationsSqlServer, MsSqlServer, MySql, MySqlConnector, PostgreSql
InputDataTable or IEnumerable<TEntity>
InterfaceIBulkInsert
Sync/AsyncInsert() and InsertAsync()

Class Hierarchy ​

mermaid
classDiagram
    class IBulkInsert {
        <<interface>>
        +DataTable Table
        +Insert()
        +InsertAsync()
        +Dispose()
    }

    class AbstractBulkInsert {
        <<abstract>>
        +DataTable Table
        +IDbSession DbSession
        +Insert()*
        +InsertAsync()*
        +Dispose()
    }

    class SqlServerBulkInsert {
        +SqlBulkCopyOptions Options
        +Insert()
        +InsertAsync()
    }

    class MsSqlServerBulkInsert {
        +SqlBulkCopyOptions Options
        +Insert()
        +InsertAsync()
    }

    class MySqlBulkInsert {
        +String SecureFilePriv
        +String DateTimeFormat
        +List~string~ Expressions
        +Insert()
        +InsertAsync()
        -ToCSV() string
    }

    class MySqlConnectorBulkInsert {
        +String SecureFilePriv
        +String DateTimeFormat
        +Insert()
        +InsertAsync()
    }

    class PostgreSqlBulkInsert {
        +Insert()
        +InsertAsync()
        -InsertImpl()
    }

    IBulkInsert <|.. AbstractBulkInsert
    AbstractBulkInsert <|-- SqlServerBulkInsert
    AbstractBulkInsert <|-- MsSqlServerBulkInsert
    AbstractBulkInsert <|-- MySqlBulkInsert
    AbstractBulkInsert <|-- MySqlConnectorBulkInsert
    AbstractBulkInsert <|-- PostgreSqlBulkInsert

    style IBulkInsert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style AbstractBulkInsert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style SqlServerBulkInsert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style MsSqlServerBulkInsert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style MySqlBulkInsert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style MySqlConnectorBulkInsert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style PostgreSqlBulkInsert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

How Each Database Provider Works ​

mermaid
sequenceDiagram
autonumber
    participant App as Application
    participant Bulk as IBulkInsert
    participant Session as IDbSession
    participant DB as Database

    App->>Bulk: Table = dataTable (or Insert(list))
    Bulk->>Session: Open()
    Session->>DB: Open connection

    alt SQL Server
        Bulk->>DB: SqlBulkCopy.WriteToServer(Table)
    else MySQL / MySqlConnector
        Bulk->>Bulk: Write Table to CSV file
        Bulk->>DB: MySqlBulkLoader.Load(fileName)
        Bulk->>Bulk: Delete temp CSV file
    else PostgreSQL
        Bulk->>DB: BeginBinaryImport(COPY ... FROM STDIN)
        loop Each DataRow
            Bulk->>DB: writer.StartRow() + writer.Write(cell)
        end
        Bulk->>DB: writer.Complete()
    end

    Bulk-->>App: Done

Data Flow ​

mermaid
flowchart TD
    subgraph Input["Data Input Options"]
        style Input fill:#161b22,stroke:#30363d,color:#e6edf3
        Entities["IEnumerable~TEntity~"] --> ToDT["BulkExtensions.ToDataTable()"]
        ManualDT["DataTable (manual)"]
    end

    subgraph Process["Bulk Insert Process"]
        style Process fill:#161b22,stroke:#30363d,color:#e6edf3
        ToDT --> DT["DataTable"]
        ManualDT --> DT
        DT --> SetTable["IBulkInsert.Table = dataTable"]
        SetTable --> Insert["Insert() or InsertAsync()"]
        Insert --> Open["DbSession.Open()"]
        Open --> Native["Native bulk copy API"]
    end

    style Entities fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style ToDT fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style ManualDT fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style DT fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style SetTable fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Insert fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Open fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Native fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

Usage ​

Convert Entities to DataTable ​

The BulkExtensions.ToDataTable<T>() extension method converts an IEnumerable<T> to a DataTable, using SmartSql's entity metadata cache for column definitions:

csharp
var entities = new List<User> { /* ... */ };
DataTable dataTable = entities.ToDataTable();

Bulk Insert Directly from Entity List ​

The Insert<T>() and InsertAsync<T>() extension methods combine conversion and insertion:

csharp
// SQL Server
var bulkInsert = new SmartSql.Bulk.SqlServer.BulkInsert(dbSession);
await bulkInsert.InsertAsync(userList);

// PostgreSQL
var bulkInsert = new SmartSql.Bulk.PostgreSql.BulkInsert(dbSession);
await bulkInsert.InsertAsync(orderList);

Bulk Insert with DataTable ​

csharp
var bulkInsert = new SmartSql.Bulk.MySql.BulkInsert(dbSession)
{
    SecureFilePriv = "/tmp",
    DateTimeFormat = "yyyy-MM-dd HH:mm:ss"
};
bulkInsert.Table = dataTable;
bulkInsert.Insert();

Provider-Specific Options ​

MySQL / MySqlConnector ​

PropertyTypeDefaultDescription
SecureFilePrivstringAppDomain base directoryDirectory for temp CSV files
DateTimeFormatstring"yyyy-MM-dd HH:mm:ss"DateTime format in CSV
ExpressionsList<string>emptyMySqlBulkLoader expressions
_fieldTerminatorstring","CSV field delimiter
_fieldQuotationCharacterchar"CSV quote character
_escapeCharacterchar"CSV escape character
_lineTerminatorstring"\r\n"CSV line terminator

SQL Server / MsSqlServer ​

PropertyTypeDefaultDescription
OptionsSqlBulkCopyOptionsDefaultBulk copy behavior flags

PostgreSQL ​

PostgreSQL bulk insert uses NpgsqlConnection.BeginBinaryImport() with the COPY ... FROM STDIN (FORMAT BINARY) command. For JSONB columns, set the DataTypeName extended property on the DataColumn:

csharp
DataColumn col = dataTable.Columns["Metadata"];
col.ExtendedProperties.Add("DataTypeName", "JSONB");

Package Mapping ​

NuGet PackageUnderlying DriverMechanism
SmartSql.Bulk.SqlServerSystem.Data.SqlClientSqlBulkCopy
SmartSql.Bulk.MsSqlServerMicrosoft.Data.SqlClientSqlBulkCopy
SmartSql.Bulk.MySqlMySql.Data.MySqlClientMySqlBulkLoader via CSV
SmartSql.Bulk.MySqlConnectorMySqlConnectorMySqlBulkLoader via CSV
SmartSql.Bulk.PostgreSqlNpgsqlBeginBinaryImport (COPY BINARY)

INFO

SmartSql.Bulk.SqlServer and SmartSql.Bulk.MsSqlServer use the same source file with conditional compilation (#if MicrosoftSqlClient). Choose the package matching your SqlClient dependency.

Cross-References ​

  • Type Handlers -- Custom type handlers affect how entity properties are converted to DataTable values via BulkExtensions.ToDataTable<T>().
  • DI Integration -- Register IBulkInsert implementations in the DI container.

References ​

Released under the MIT License.