Skip to content

Commit f1b361e

Browse files
committed
Fix SqlServer bulkinsert issues breaking the integration tests.
This issue was caused by a combination of a recent changes to keepIdentity handling and some legacy handling that automatically enables keepIdentity whenever a table has an identity value. As there was no way to override the behavior it was no longer possible to autogenerate identity values, as we (and probably our users) do in many scenarios. This caused > 20 test failures. As there is no easy way to unbreak this I removed the automatically setting keep-identity and cleaned up the arguments to properly allow setting the value as normal Enum (without nullable wrapper). At the same time I introduced ILogger like in the non-bulk api and forwarded that wherever possible (and where I did not forget something). This fixes all the SqlServer Bulkinsert integrationtests.
1 parent 5ccb379 commit f1b361e

File tree

18 files changed

+1421
-1295
lines changed

18 files changed

+1421
-1295
lines changed

RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations/Base/BulkDelete.cs

Lines changed: 98 additions & 85 deletions
Large diffs are not rendered by default.

RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations/Base/BulkInsert.cs

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
using RepoDb.Extensions;
2-
using System;
1+
using System;
32
using System.Collections.Generic;
43
using System.Data;
54
using System.Data.Common;
65
using System.Linq;
76
using System.Threading;
87
using System.Threading.Tasks;
98
using Microsoft.Data.SqlClient;
9+
using RepoDb.Extensions;
1010
using RepoDb.Interfaces;
1111

1212
namespace RepoDb
@@ -30,18 +30,20 @@ public static partial class SqlConnectionExtension
3030
/// <param name="isReturnIdentity"></param>
3131
/// <param name="usePhysicalPseudoTempTable"></param>
3232
/// <param name="transaction"></param>
33+
/// <param name="trace"></param>
3334
/// <returns></returns>
3435
private static int BulkInsertInternalBase<TEntity>(SqlConnection connection,
3536
string tableName,
3637
IEnumerable<TEntity> entities,
37-
IEnumerable<BulkInsertMapItem> mappings = null,
38+
IEnumerable<BulkInsertMapItem>? mappings = null,
3839
SqlBulkCopyOptions options = default,
39-
string hints = null,
40+
string? hints = null,
4041
int? bulkCopyTimeout = null,
4142
int? batchSize = null,
42-
bool? isReturnIdentity = null,
43-
bool? usePhysicalPseudoTempTable = null,
44-
SqlTransaction transaction = null)
43+
bool isReturnIdentity = false,
44+
bool usePhysicalPseudoTempTable = false,
45+
SqlTransaction? transaction = null,
46+
ITrace? trace = null)
4547
where TEntity : class
4648
{
4749
// Validate
@@ -140,7 +142,7 @@ private static int BulkInsertInternalBase<TEntity>(SqlConnection connection,
140142

141143
// Drop the table after used
142144
sql = GetDropTemporaryTableSqlText(tempTableName, dbSetting);
143-
connection.ExecuteNonQuery(sql, transaction: transaction);
145+
connection.ExecuteNonQuery(sql, transaction: transaction, trace: trace);
144146
}
145147

146148
CommitTransaction(transaction, hasTransaction);
@@ -154,7 +156,7 @@ private static int BulkInsertInternalBase<TEntity>(SqlConnection connection,
154156
{
155157
DisposeTransaction(transaction, hasTransaction);
156158
}
157-
159+
158160
// Return the result
159161
return result;
160162
}
@@ -174,11 +176,11 @@ private static int BulkInsertInternalBase<TEntity>(SqlConnection connection,
174176
internal static int BulkInsertInternalBase(SqlConnection connection,
175177
string tableName,
176178
DbDataReader reader,
177-
IEnumerable<BulkInsertMapItem> mappings = null,
179+
IEnumerable<BulkInsertMapItem>? mappings = null,
178180
SqlBulkCopyOptions options = default,
179181
int? bulkCopyTimeout = null,
180182
int? batchSize = null,
181-
SqlTransaction transaction = null)
183+
SqlTransaction? transaction = null)
182184
{
183185
// Validate
184186
if (!reader.HasRows)
@@ -253,7 +255,7 @@ internal static int BulkInsertInternalBase(SqlConnection connection,
253255
{
254256
DisposeTransaction(transaction, hasTransaction);
255257
}
256-
258+
257259
// Return the result
258260
return result;
259261
}
@@ -273,19 +275,21 @@ internal static int BulkInsertInternalBase(SqlConnection connection,
273275
/// <param name="isReturnIdentity"></param>
274276
/// <param name="usePhysicalPseudoTempTable"></param>
275277
/// <param name="transaction"></param>
278+
/// <param name="trace"></param>
276279
/// <returns></returns>
277280
internal static int BulkInsertInternalBase(SqlConnection connection,
278281
string tableName,
279282
DataTable dataTable,
280283
DataRowState? rowState = null,
281-
IEnumerable<BulkInsertMapItem> mappings = null,
284+
IEnumerable<BulkInsertMapItem>? mappings = null,
282285
SqlBulkCopyOptions options = default,
283-
string hints = null,
286+
string? hints = null,
284287
int? bulkCopyTimeout = null,
285288
int? batchSize = null,
286-
bool? isReturnIdentity = null,
287-
bool? usePhysicalPseudoTempTable = null,
288-
SqlTransaction transaction = null)
289+
bool isReturnIdentity = false,
290+
bool usePhysicalPseudoTempTable = false,
291+
SqlTransaction? transaction = null,
292+
ITrace? trace = null)
289293
{
290294
// Validate
291295
if (dataTable?.Rows.Count <= 0)
@@ -391,7 +395,7 @@ internal static int BulkInsertInternalBase(SqlConnection connection,
391395

392396
// Drop the table after used
393397
sql = GetDropTemporaryTableSqlText(tempTableName, dbSetting);
394-
connection.ExecuteNonQuery(sql, transaction: transaction);
398+
connection.ExecuteNonQuery(sql, transaction: transaction, trace: trace);
395399
}
396400
}
397401

@@ -406,7 +410,7 @@ internal static int BulkInsertInternalBase(SqlConnection connection,
406410
{
407411
DisposeTransaction(transaction, hasTransaction);
408412
}
409-
413+
410414
// Return the result
411415
return result;
412416
}
@@ -430,19 +434,21 @@ internal static int BulkInsertInternalBase(SqlConnection connection,
430434
/// <param name="isReturnIdentity"></param>
431435
/// <param name="usePhysicalPseudoTempTable"></param>
432436
/// <param name="transaction"></param>
437+
/// <param name="trace"></param>
433438
/// <param name="cancellationToken"></param>
434439
/// <returns></returns>
435440
private static async Task<int> BulkInsertAsyncInternalBase<TEntity>(SqlConnection connection,
436441
string tableName,
437442
IEnumerable<TEntity> entities,
438-
IEnumerable<BulkInsertMapItem> mappings = null,
443+
IEnumerable<BulkInsertMapItem>? mappings = null,
439444
SqlBulkCopyOptions options = default,
440-
string hints = null,
445+
string? hints = null,
441446
int? bulkCopyTimeout = null,
442447
int? batchSize = null,
443-
bool? isReturnIdentity = null,
444-
bool? usePhysicalPseudoTempTable = null,
445-
SqlTransaction transaction = null,
448+
bool isReturnIdentity = false,
449+
bool usePhysicalPseudoTempTable = false,
450+
SqlTransaction? transaction = null,
451+
ITrace? trace = null,
446452
CancellationToken cancellationToken = default)
447453
where TEntity : class
448454
{
@@ -545,7 +551,7 @@ private static async Task<int> BulkInsertAsyncInternalBase<TEntity>(SqlConnectio
545551

546552
// Drop the table after used
547553
sql = GetDropTemporaryTableSqlText(tempTableName, dbSetting);
548-
await connection.ExecuteNonQueryAsync(sql, transaction: transaction, cancellationToken: cancellationToken);
554+
await connection.ExecuteNonQueryAsync(sql, transaction: transaction, trace: trace, cancellationToken: cancellationToken);
549555
}
550556

551557
CommitTransaction(transaction, hasTransaction);
@@ -559,11 +565,11 @@ private static async Task<int> BulkInsertAsyncInternalBase<TEntity>(SqlConnectio
559565
{
560566
DisposeTransaction(transaction, hasTransaction);
561567
}
562-
568+
563569
// Return the result
564570
return result;
565571
}
566-
572+
567573
/// <summary>
568574
///
569575
/// </summary>
@@ -580,11 +586,11 @@ private static async Task<int> BulkInsertAsyncInternalBase<TEntity>(SqlConnectio
580586
internal static async Task<int> BulkInsertAsyncInternalBase(SqlConnection connection,
581587
string tableName,
582588
DbDataReader reader,
583-
IEnumerable<BulkInsertMapItem> mappings = null,
589+
IEnumerable<BulkInsertMapItem>? mappings = null,
584590
SqlBulkCopyOptions options = default,
585591
int? bulkCopyTimeout = null,
586592
int? batchSize = null,
587-
SqlTransaction transaction = null,
593+
SqlTransaction? transaction = null,
588594
CancellationToken cancellationToken = default)
589595
{
590596
// Validate
@@ -661,7 +667,7 @@ internal static async Task<int> BulkInsertAsyncInternalBase(SqlConnection connec
661667
{
662668
DisposeTransaction(transaction, hasTransaction);
663669
}
664-
670+
665671
// Return the result
666672
return result;
667673
}
@@ -681,20 +687,22 @@ internal static async Task<int> BulkInsertAsyncInternalBase(SqlConnection connec
681687
/// <param name="isReturnIdentity"></param>
682688
/// <param name="usePhysicalPseudoTempTable"></param>
683689
/// <param name="transaction"></param>
690+
/// <param name="trace"></param>
684691
/// <param name="cancellationToken"></param>
685692
/// <returns></returns>
686693
internal static async Task<int> BulkInsertAsyncInternalBase(SqlConnection connection,
687694
string tableName,
688695
DataTable dataTable,
689696
DataRowState? rowState = null,
690-
IEnumerable<BulkInsertMapItem> mappings = null,
697+
IEnumerable<BulkInsertMapItem>? mappings = null,
691698
SqlBulkCopyOptions options = default,
692-
string hints = null,
699+
string? hints = null,
693700
int? bulkCopyTimeout = null,
694701
int? batchSize = null,
695-
bool? isReturnIdentity = null,
696-
bool? usePhysicalPseudoTempTable = null,
697-
SqlTransaction transaction = null,
702+
bool isReturnIdentity = false,
703+
bool usePhysicalPseudoTempTable = false,
704+
SqlTransaction? transaction = null,
705+
ITrace? trace = null,
698706
CancellationToken cancellationToken = default)
699707
{
700708
// Validate
@@ -752,7 +760,7 @@ internal static async Task<int> BulkInsertAsyncInternalBase(SqlConnection connec
752760

753761
// Pseudo temp table
754762
var withPseudoExecution = isReturnIdentity == true && identityDbField != null;
755-
var tempTableName = await CreateBulkInsertTempTableIfNecessaryAsync(connection,
763+
var tempTableName = await CreateBulkInsertTempTableIfNecessaryAsync(connection,
756764
tableName,
757765
usePhysicalPseudoTempTable,
758766
transaction,
@@ -803,7 +811,7 @@ internal static async Task<int> BulkInsertAsyncInternalBase(SqlConnection connec
803811

804812
// Drop the table after used
805813
sql = GetDropTemporaryTableSqlText(tempTableName, dbSetting);
806-
await connection.ExecuteNonQueryAsync(sql, transaction: transaction, cancellationToken: cancellationToken);
814+
await connection.ExecuteNonQueryAsync(sql, transaction: transaction, trace: trace, cancellationToken: cancellationToken);
807815
}
808816
}
809817

@@ -818,30 +826,31 @@ internal static async Task<int> BulkInsertAsyncInternalBase(SqlConnection connec
818826
{
819827
DisposeTransaction(transaction, hasTransaction);
820828
}
821-
829+
822830
// Return the result
823831
return result;
824832
}
825833

826834
#endregion
827-
835+
828836
private static string CreateBulkInsertTempTableIfNecessary<TSqlTransaction>(
829837
IDbConnection connection,
830838
string tableName,
831839
bool? usePhysicalPseudoTempTable,
832840
TSqlTransaction transaction,
833841
bool withPseudoExecution,
834842
IDbSetting dbSetting,
835-
IEnumerable<Field> fields)
843+
IEnumerable<Field> fields,
844+
ITrace? trace = null)
836845
where TSqlTransaction : DbTransaction
837846
{
838-
if (withPseudoExecution == false)
847+
if (withPseudoExecution == false)
839848
return null;
840849

841850
var tempTableName = CreateBulkInsertTempTableName(tableName, usePhysicalPseudoTempTable, dbSetting);
842851
var sql = GetCreateTemporaryTableSqlText(tableName, tempTableName, fields, dbSetting, true);
843852

844-
connection.ExecuteNonQuery(sql, transaction: transaction);
853+
connection.ExecuteNonQuery(sql, transaction: transaction, trace: trace);
845854

846855
return tempTableName;
847856
}
@@ -852,17 +861,18 @@ private static async Task<string> CreateBulkInsertTempTableIfNecessaryAsync<TSql
852861
TSqlTransaction transaction,
853862
bool withPseudoExecution,
854863
IDbSetting dbSetting,
855-
IEnumerable<Field> fields,
856-
CancellationToken cancellationToken)
864+
IEnumerable<Field> fields,
865+
CancellationToken cancellationToken,
866+
ITrace? trace = null)
857867
where TSqlTransaction : DbTransaction
858868
{
859-
if (withPseudoExecution == false)
869+
if (withPseudoExecution == false)
860870
return null;
861871

862872
var tempTableName = CreateBulkInsertTempTableName(tableName, usePhysicalPseudoTempTable, dbSetting);
863873
var sql = GetCreateTemporaryTableSqlText(tableName, tempTableName, fields, dbSetting, true);
864874

865-
await connection.ExecuteNonQueryAsync(sql, transaction: transaction, cancellationToken: cancellationToken);
875+
await connection.ExecuteNonQueryAsync(sql, transaction: transaction, trace: trace, cancellationToken: cancellationToken);
866876

867877
return tempTableName;
868878
}

0 commit comments

Comments
 (0)