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.