Skip to content

Commit 1ae0e5f

Browse files
author
fabien.menager
committed
Add docs
1 parent 7da7f79 commit 1ae0e5f

10 files changed

Lines changed: 2729 additions & 12 deletions

File tree

.github/workflows/static.yml

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Simple workflow for deploying static content to GitHub Pages
2-
name: Deploy static content to Pages
1+
name: Deploy site to Pages
32

43
on:
5-
# Runs on pushes targeting the default branch
4+
# Runs on pushes targeting the `main` branch. Change this to `master` if you're
5+
# using the `master` branch as the default branch.
66
push:
7-
branches: ["main"]
7+
branches: [main]
88

99
# Allows you to run this workflow manually from the Actions tab
1010
workflow_dispatch:
@@ -18,25 +18,45 @@ permissions:
1818
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
1919
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
2020
concurrency:
21-
group: "pages"
21+
group: pages
2222
cancel-in-progress: false
2323

2424
jobs:
25-
# Single deploy job since we're just deploying
26-
deploy:
27-
environment:
28-
name: github-pages
29-
url: ${{ steps.deployment.outputs.page_url }}
25+
# Build job
26+
build:
3027
runs-on: ubuntu-latest
3128
steps:
3229
- name: Checkout
3330
uses: actions/checkout@v4
31+
# - uses: pnpm/action-setup@v3 # Uncomment this block if you're using pnpm
32+
# with:
33+
# version: 9 # Not needed if you've set "packageManager" in package.json
34+
# - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
35+
- name: Setup Node
36+
uses: actions/setup-node@v4
37+
with:
38+
node-version: 22
39+
cache: npm # or pnpm / yarn
3440
- name: Setup Pages
35-
uses: actions/configure-pages@v5
41+
uses: actions/configure-pages@v4
42+
- name: Install dependencies
43+
run: npm ci # or pnpm install / yarn install / bun install
44+
- name: Build with VitePress
45+
run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build
3646
- name: Upload artifact
3747
uses: actions/upload-pages-artifact@v3
3848
with:
39-
path: 'pages'
49+
path: docs/.vitepress/dist
50+
51+
# Deployment job
52+
deploy:
53+
environment:
54+
name: github-pages
55+
url: ${{ steps.deployment.outputs.page_url }}
56+
needs: build
57+
runs-on: ubuntu-latest
58+
name: Deploy
59+
steps:
4060
- name: Deploy to GitHub Pages
4161
id: deployment
4262
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,7 @@ fabric.properties
9191

9292
# Visual Studio Files
9393
.vs
94+
95+
# Vitepress
96+
docs/.vitepress/dist
97+
docs/.vitepress/cache

docs/.vitepress/config.mts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {defineConfig} from 'vitepress'
2+
3+
// https://vitepress.dev/reference/site-config
4+
export default defineConfig({
5+
title: "PhenX EFCore BulkInsert",
6+
description: "Super fast bulk insert for EF Core",
7+
themeConfig: {
8+
outline: "deep",
9+
search: {
10+
provider: 'local'
11+
},
12+
13+
// https://vitepress.dev/reference/default-theme-config
14+
nav: [
15+
{text: 'Home', link: '/'},
16+
{text: 'Documentation', link: '/documentation'},
17+
],
18+
19+
sidebar: [
20+
{
21+
text: 'Getting started',
22+
items: [
23+
{text: 'Installation', link: '/getting-started#installation'},
24+
{text: 'Usage', link: '/getting-started#usage'},
25+
]
26+
},
27+
{
28+
text: 'Documentation',
29+
link: '/documentation'
30+
},
31+
{
32+
text: 'Limitations',
33+
link: '/limitations'
34+
},
35+
],
36+
37+
editLink: {
38+
pattern: 'https://github.com/PhenX/PhenX.EntityFrameworkCore.BulkInsert/edit/main/README.md/edit/main/docs/:path',
39+
text: 'Edit this page on GitHub'
40+
},
41+
42+
lastUpdated: {
43+
text: 'Updated at',
44+
formatOptions: {
45+
dateStyle: 'full',
46+
timeStyle: 'medium'
47+
}
48+
},
49+
50+
socialLinks: [
51+
{
52+
icon: 'github', link: 'https://github.com/PhenX/PhenX.EntityFrameworkCore.BulkInsert',
53+
}
54+
],
55+
56+
externalLinkIcon: true,
57+
58+
footer: {
59+
message: 'Released under the MIT License.',
60+
copyright: 'Copyright © 2025-present Fabien Ménager'
61+
}
62+
}
63+
})

docs/documentation.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
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

Comments
 (0)