Skip to content

Commit 1cba602

Browse files
author
fabien.menager
committed
Refactor bulk insert provider classes to improve organization and enhance usability of options
1 parent c16dee5 commit 1cba602

24 files changed

Lines changed: 110 additions & 94 deletions

src/EntityFrameworkCore.ExecuteInsert.PostgreSql/PostgreSqlBulkInsertProvider.cs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Data.Common;
1+
using EntityFrameworkCore.ExecuteInsert.Options;
22

33
using Microsoft.EntityFrameworkCore;
44

@@ -21,26 +21,32 @@ private string GetBinaryImportCommand(DbContext context, Type entityType, string
2121
return $"COPY {tableName} ({string.Join(", ", columns)}) FROM STDIN (FORMAT BINARY)";
2222
}
2323

24-
protected override async Task BulkImport<T>(DbContext context, DbConnection connection, IEnumerable<T> entities,
25-
string tableName, PropertyAccessor[] properties, BulkInsertOptions options, CancellationToken ctk) where T : class
24+
protected override async Task BulkInsert<T>(
25+
DbContext context,
26+
IEnumerable<T> entities,
27+
string tableName,
28+
PropertyAccessor[] properties,
29+
BulkInsertOptions options,
30+
CancellationToken ctk) where T : class
2631
{
32+
var connection = (NpgsqlConnection)context.Database.GetDbConnection();
33+
2734
var importCommand = GetBinaryImportCommand(context, typeof(T), tableName);
2835

29-
await using (var writer = await ((NpgsqlConnection)connection).BeginBinaryImportAsync(importCommand, ctk))
36+
await using var writer = await connection.BeginBinaryImportAsync(importCommand, ctk);
37+
38+
foreach (var entity in entities)
3039
{
31-
foreach (var entity in entities)
32-
{
33-
await writer.StartRowAsync(ctk);
40+
await writer.StartRowAsync(ctk);
3441

35-
foreach (var property in properties)
36-
{
37-
var value = property.GetValue(entity);
42+
foreach (var property in properties)
43+
{
44+
var value = property.GetValue(entity);
3845

39-
await writer.WriteAsync(value, ctk);
40-
}
46+
await writer.WriteAsync(value, ctk);
4147
}
42-
43-
await writer.CompleteAsync(ctk);
4448
}
49+
50+
await writer.CompleteAsync(ctk);
4551
}
4652
}

src/EntityFrameworkCore.ExecuteInsert.PostgreSql/PostgresBulkInsertExtensions.cs renamed to src/EntityFrameworkCore.ExecuteInsert.PostgreSql/PostgreSqlDbContextOptionsExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace EntityFrameworkCore.ExecuteInsert.PostgreSql;
55

6-
public static class PostgresBulkInsertExtensions
6+
public static class PostgreSqlDbContextOptionsExtensions
77
{
88
public static DbContextOptionsBuilder UseExecuteInsertPostgres(this DbContextOptionsBuilder optionsBuilder)
99
{

src/EntityFrameworkCore.ExecuteInsert.PostgreSql/PostgreSqlDialectBuilder.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace EntityFrameworkCore.ExecuteInsert.PostgreSql;
1+
using EntityFrameworkCore.ExecuteInsert.Dialect;
2+
3+
namespace EntityFrameworkCore.ExecuteInsert.PostgreSql;
24

35
public class PostgreSqlDialectBuilder : SqlDialectBuilder
46
{

src/EntityFrameworkCore.ExecuteInsert.SqlServer/SqlServerBulkInsertProvider.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Data.Common;
1+
using EntityFrameworkCore.ExecuteInsert.Options;
22

33
using Microsoft.Data.SqlClient;
44
using Microsoft.EntityFrameworkCore;
@@ -15,10 +15,12 @@ public class SqlServerBulkInsertProvider : BulkInsertProviderBase<SqlServerDiale
1515

1616
protected override string GetTempTableName(string tableName) => $"#_temp_bulk_insert_{tableName}";
1717

18-
protected override async Task BulkImport<T>(DbContext context, DbConnection connection, IEnumerable<T> entities,
18+
protected override async Task BulkInsert<T>(DbContext context, IEnumerable<T> entities,
1919
string tableName,
2020
PropertyAccessor[] properties, BulkInsertOptions options, CancellationToken ctk)
2121
{
22+
var connection = context.Database.GetDbConnection();
23+
2224
await using var t = (SqlTransaction) await connection.BeginTransactionAsync(ctk); // TODO option
2325

2426
using var bulkCopy = new SqlBulkCopy(connection as SqlConnection, SqlBulkCopyOptions.TableLock, t);

src/EntityFrameworkCore.ExecuteInsert.SqlServer/SqlServerBulkInsertExtensions.cs renamed to src/EntityFrameworkCore.ExecuteInsert.SqlServer/SqlServerDbContextOptionsExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace EntityFrameworkCore.ExecuteInsert.SqlServer;
55

6-
public static class SqlServerBulkInsertExtensions
6+
public static class SqlServerDbContextOptionsExtensions
77
{
88
public static DbContextOptionsBuilder UseExecuteInsertSqlServer(this DbContextOptionsBuilder optionsBuilder)
99
{

src/EntityFrameworkCore.ExecuteInsert.SqlServer/SqlServerDialectBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using System.Linq.Expressions;
22
using System.Text;
33

4-
using EntityFrameworkCore.ExecuteInsert.OnConflict;
4+
using EntityFrameworkCore.ExecuteInsert.Dialect;
5+
using EntityFrameworkCore.ExecuteInsert.Options;
56

67
using Microsoft.EntityFrameworkCore;
78
using Microsoft.EntityFrameworkCore.Metadata;

src/EntityFrameworkCore.ExecuteInsert.Sqlite/SqliteBulkInsertProvider.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
using System.Data.Common;
2-
using System.Text;
32

4-
using EntityFrameworkCore.ExecuteInsert.Helpers;
5-
using EntityFrameworkCore.ExecuteInsert.OnConflict;
3+
using EntityFrameworkCore.ExecuteInsert.Extensions;
4+
using EntityFrameworkCore.ExecuteInsert.Options;
5+
66
using Microsoft.EntityFrameworkCore;
7-
using Microsoft.EntityFrameworkCore.Metadata;
87
using Microsoft.Data.Sqlite;
98

109
namespace EntityFrameworkCore.ExecuteInsert.Sqlite;
@@ -69,11 +68,11 @@ private static SqliteType GetSqliteType(Type clrType)
6968
throw new InvalidOperationException("Unknown Sqlite type for " + clrType);
7069
}
7170

72-
private DbCommand GetInsertCommand(DbContext context, DbConnection connection, Type entityType, string tableName,
71+
private DbCommand GetInsertCommand(DbContext context, Type entityType, string tableName,
7372
int batchSize)
7473
{
75-
var columns = DatabaseHelper.GetProperties(context, entityType, false);
76-
var cmd = connection.CreateCommand();
74+
var columns = context.GetProperties(entityType, false);
75+
var cmd = context.Database.GetDbConnection().CreateCommand();
7776

7877
var sqliteColumns = columns
7978
.Select(c => new
@@ -109,16 +108,18 @@ private DbCommand GetInsertCommand(DbContext context, DbConnection connection, T
109108
return cmd;
110109
}
111110

112-
protected override async Task BulkImport<T>(DbContext context, DbConnection connection, IEnumerable<T> entities,
111+
protected override async Task BulkInsert<T>(DbContext context, IEnumerable<T> entities,
113112
string tableName, PropertyAccessor[] properties, BulkInsertOptions options, CancellationToken ctk) where T : class
114113
{
114+
var connection = context.Database.GetDbConnection();
115+
115116
await using var transaction = await connection.BeginTransactionAsync(ctk);
116117

117118
const int maxParams = 1000;
118119
var batchSize = options.BatchSize ?? 5;
119120
batchSize = Math.Min(batchSize, maxParams / properties.Length);
120121

121-
await using var insertCommand = GetInsertCommand(context, connection, typeof(T), tableName, batchSize);
122+
await using var insertCommand = GetInsertCommand(context, typeof(T), tableName, batchSize);
122123

123124
foreach (var chunk in entities.Chunk(batchSize))
124125
{
@@ -132,7 +133,7 @@ protected override async Task BulkImport<T>(DbContext context, DbConnection conn
132133
// Last chunk
133134
else
134135
{
135-
var partialInsertCommand = GetInsertCommand(context, connection, typeof(T), tableName, chunk.Length);
136+
var partialInsertCommand = GetInsertCommand(context, typeof(T), tableName, chunk.Length);
136137
FillValues(chunk, partialInsertCommand.Parameters, properties);
137138

138139
await partialInsertCommand.ExecuteNonQueryAsync(ctk);

src/EntityFrameworkCore.ExecuteInsert.Sqlite/SqliteBulkInsertExtensions.cs renamed to src/EntityFrameworkCore.ExecuteInsert.Sqlite/SqliteDbContextOptionsExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace EntityFrameworkCore.ExecuteInsert.Sqlite;
55

6-
public static class SqliteBulkInsertExtensions
6+
public static class SqliteDbContextOptionsExtensions
77
{
88
public static DbContextOptionsBuilder UseExecuteInsertSqlite(this DbContextOptionsBuilder optionsBuilder)
99
{

src/EntityFrameworkCore.ExecuteInsert.Sqlite/SqliteDialectBuilder.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace EntityFrameworkCore.ExecuteInsert.Sqlite;
1+
using EntityFrameworkCore.ExecuteInsert.Dialect;
2+
3+
namespace EntityFrameworkCore.ExecuteInsert.Sqlite;
24

35
public class SqliteDialectBuilder : SqlDialectBuilder
46
{

src/EntityFrameworkCore.ExecuteInsert/Abstractions/IBulkInsertProvider.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
using EntityFrameworkCore.ExecuteInsert.OnConflict;
1+
using EntityFrameworkCore.ExecuteInsert.Options;
22

33
using Microsoft.EntityFrameworkCore;
44

55
namespace EntityFrameworkCore.ExecuteInsert.Abstractions;
66

77
public interface IBulkInsertProvider
88
{
9-
Task<List<T>> BulkInsertWithIdentityAsync<T>(
9+
internal Task<List<T>> BulkInsertWithIdentityAsync<T>(
1010
DbContext context,
1111
IEnumerable<T> entities,
1212
BulkInsertOptions options,
1313
OnConflictOptions? onConflict = null,
1414
CancellationToken ctk = default
1515
) where T : class;
1616

17-
Task BulkInsertWithoutReturnAsync<T>(
17+
internal Task BulkInsertWithoutReturnAsync<T>(
1818
DbContext context,
1919
IEnumerable<T> entities,
2020
BulkInsertOptions options,

0 commit comments

Comments
 (0)