|
| 1 | +# Configure the DbContext |
| 2 | + |
| 3 | +Register the bulk insert provider in your `DbContextOptions`: |
| 4 | + |
| 5 | +```csharp{6,8,10,12,14} |
| 6 | +services.AddDbContext<MyDbContext>(options => |
| 7 | +{ |
| 8 | + options |
| 9 | + // .UseSqlServer(connectionString) // or UseNpgsql or UseSqlite, as appropriate |
| 10 | +
|
| 11 | + .UseBulkInsertPostgreSql() |
| 12 | + // OR |
| 13 | + .UseBulkInsertSqlServer() |
| 14 | + // OR |
| 15 | + .UseBulkInsertSqlite() |
| 16 | + // OR |
| 17 | + .UseBulkInsertMySql() |
| 18 | + // OR |
| 19 | + .UseBulkInsertOracle() |
| 20 | + ; |
| 21 | +}); |
| 22 | +``` |
| 23 | + |
| 24 | +# Insert methods |
| 25 | + |
| 26 | +There are two groups of methods for inserting data into the database: |
| 27 | + |
| 28 | +* `ExecuteBulkInsert` - inserts the entities as fast as possible, without returning the inserted entities. This is suitable for scenarios where you don't need to access the inserted data immediately. |
| 29 | +* `ExecuteBulkInsertReturnEntities` - inserts the entities and returns the inserted entities. This is useful when you need to access the inserted data right after the insertion, but it's slower because it requires creating an intermediate temporary table. |
| 30 | + |
| 31 | +Each method has an asynchronous version (`ExecuteBulkInsertAsync` and `ExecuteBulkInsertReturnEntitiesAsync`). |
| 32 | + |
| 33 | +These methods all take the same parameters: |
| 34 | + |
| 35 | +* `IEnumerable<T>` - the collection of entities to insert. |
| 36 | +* `Action<BulkInsertOptions<T>>` - an optional action to configure the bulk insert options, such as batch size, timeout, etc. |
| 37 | +* `OnConflictOptions<T>` - an optional action to configure conflict resolution options, such as ignoring conflicts or updating existing records. |
| 38 | +* `CancellationToken` - an optional cancellation token to cancel the operation, only for the asynchronous methods. |
| 39 | + |
| 40 | +### Basic usage |
| 41 | + |
| 42 | +```csharp |
| 43 | +// Asynchronously |
| 44 | +await dbContext.ExecuteBulkInsertAsync(entities); |
| 45 | + |
| 46 | +// Or synchronously |
| 47 | +dbContext.ExecuteBulkInsert(entities); |
| 48 | +``` |
| 49 | + |
| 50 | +### Bulk insert with options |
| 51 | + |
| 52 | +```csharp |
| 53 | +// Common options |
| 54 | +await dbContext.ExecuteBulkInsertAsync(entities, options => |
| 55 | +{ |
| 56 | + options.BatchSize = 1000; // Set the batch size for the insert operation, the default value is different for each provider |
| 57 | +}); |
| 58 | + |
| 59 | +// Provider specific options, when available, example for SQL Server |
| 60 | +await dbContext.ExecuteBulkInsertAsync(entities, (SqlServerBulkInsertOptions o) => // <<< here specify the SQL Server options class |
| 61 | +{ |
| 62 | + options.EnableStreaming = true; // Enable streaming for SQL Server |
| 63 | +}); |
| 64 | + |
| 65 | +// Provider specific options, supporting multiple providers |
| 66 | +await dbContext.ExecuteBulkInsertAsync(entities, o => |
| 67 | +{ |
| 68 | + o.MoveRows = true; |
| 69 | + |
| 70 | + if (o is SqlServerBulkInsertOptions sqlServerOptions) |
| 71 | + { |
| 72 | + sqlServerOptions.EnableStreaming = true; |
| 73 | + } |
| 74 | + else if (o is MySqlBulkInsertOptions mysqlOptions) |
| 75 | + { |
| 76 | + mysqlOptions.BatchSize = 1000; |
| 77 | + } |
| 78 | +}); |
| 79 | +``` |
| 80 | + |
| 81 | +### Returning inserted entities |
| 82 | + |
| 83 | +```csharp |
| 84 | +await dbContext.ExecuteBulkInsertReturnEntitiesAsync(entities); |
| 85 | +``` |
| 86 | + |
| 87 | +### Conflict resolution / merge / upsert |
| 88 | + |
| 89 | +Conflict resolution works by specifying columns that should be used to detect conflicts and the action to take when |
| 90 | +a conflict is detected (e.g., update existing rows), using the `onConflict` parameter. |
| 91 | + |
| 92 | +* The conflicting columns are specified with the `Match` property and must have a unique constraint in the database. |
| 93 | +* The action to take when a conflict is detected is specified with the `Update` property. If not specified, the default action is to do nothing (i.e., skip the conflicting rows). |
| 94 | +* You can also specify the condition for the update action using either the `Where` or the `RawWhere` property. If not specified, the update action will be applied to all conflicting rows. |
| 95 | + |
| 96 | +```csharp |
| 97 | +await dbContext.ExecuteBulkInsertAsync(entities, onConflict: new OnConflictOptions<TestEntity> |
| 98 | +{ |
| 99 | + Match = e => new |
| 100 | + { |
| 101 | + e.Name, |
| 102 | + // ...other columns to match on |
| 103 | + }, |
| 104 | + |
| 105 | + // Optional: specify the update action, if not specified, the default action is to do nothing |
| 106 | + // Excluded is the row being inserted which is in conflict, and Inserted is the row already in the database. |
| 107 | + Update = (inserted, excluded) => new TestEntity |
| 108 | + { |
| 109 | + Price = inserted.Price // Update the Price column with the new value |
| 110 | + }, |
| 111 | + |
| 112 | + // Optional: specify the condition for the update action |
| 113 | + // Excluded is the row being inserted which is in conflict, and Inserted is the row already in the database. |
| 114 | + // Using raw SQL condition |
| 115 | + RawWhere = (insertedTable, excludedTable) => $"{excludedTable}.some_price > {insertedTable}.some_price", |
| 116 | + |
| 117 | + // OR using a lambda expression |
| 118 | + Where = (inserted, excluded) => excluded.Price > inserted.Price, |
| 119 | +}); |
| 120 | +``` |
| 121 | + |
| 122 | +## Options |
| 123 | + |
| 124 | +The default values for each provider are shown in the table below. |
| 125 | + |
| 126 | +You can override these defaults by passing an action to the `ExecuteBulkInsert` or `ExecuteBulkInsertReturnEntities` methods. |
| 127 | + |
| 128 | +### BatchSize |
| 129 | + |
| 130 | +* Type: `int` |
| 131 | +* Default: |
| 132 | + * SQL Server: `50,000` |
| 133 | + * PostgreSQL: N/A (uses native bulk insert) |
| 134 | + * SQLite: `5` (INSERT statement with multiple values) |
| 135 | + * MySQL: N/A (uses native bulk insert) |
| 136 | + * Oracle: `50,000` |
| 137 | + |
| 138 | +The number of rows to insert in each batch. |
| 139 | + |
| 140 | +### CopyTimeout |
| 141 | + |
| 142 | +* Type: `TimeSpan` |
| 143 | +* Default: `10 minutes` |
| 144 | + |
| 145 | +The timeout for the bulk insert operation. |
| 146 | + |
| 147 | +### CopyGeneratedColumns |
| 148 | +* Type: `bool` |
| 149 | +* Default: `false` |
| 150 | + |
| 151 | +Copy computed/generated columns |
| 152 | + |
| 153 | +### MoveRows |
| 154 | +* Type: `bool` |
| 155 | +* Default: `false` (PostgreSQL only) |
| 156 | + |
| 157 | +Move rows between tables (PostgreSQL only), only applies when returning entities. |
| 158 | + |
| 159 | +### SRID |
| 160 | + |
| 161 | +* Type: `int` |
| 162 | +* Default: `4326` |
| 163 | + |
| 164 | +Sets the ID of the Spatial Reference System used by the Geometries to be inserted. |
| 165 | + |
| 166 | +### NotifyProgressAfter |
| 167 | + |
| 168 | +* Type: `int` |
| 169 | +* Default: `unset` |
| 170 | + |
| 171 | +Notify after X rows are copied. This is useful for tracking progress in long-running operations. |
| 172 | + |
| 173 | +### OnProgress |
| 174 | + |
| 175 | +* Type: `Action<int>` |
| 176 | +* Default: `unset` |
| 177 | + |
| 178 | +Callback for progress reporting. This is called with the number of rows copied so far. |
| 179 | + |
| 180 | +### Converters |
| 181 | + |
| 182 | +* Type: `IEnumerable<IValueConverter>` |
| 183 | +* Default: `[GeometryConverter]` (SQL Server and PostgreSQL only) |
| 184 | + |
| 185 | +List of value converters for custom types, such as spatial types. |
| 186 | + |
| 187 | +### CopyOptions |
| 188 | + |
| 189 | +* Type: `Enum` |
| 190 | +* Default: `Default` (SQL Server and Oracle only) |
| 191 | + |
| 192 | +Provider-specific copy/bulk options (`SqlBulkCopyOptions` for SQL Server, `OracleBulkCopyOptions` for Oracle, etc) |
| 193 | + |
| 194 | +### EnableStreaming |
| 195 | + |
| 196 | +* Type: `bool` |
| 197 | +* Default: `false` (SQL Server only) |
| 198 | + |
| 199 | +Enable streaming bulk copy for SQL Server |
| 200 | + |
| 201 | +### TypeProviders |
| 202 | + |
| 203 | +* Type: `IEnumerable<ITypeProvider>` |
| 204 | +* Default: `unset` (PostgreSQL only) |
| 205 | + |
| 206 | +Custom PostgreSQL type providers for handling specific data types. |
0 commit comments