Skip to content

Commit f5fd592

Browse files
authored
Feat(option): add option Command Timeout (#9)
1 parent 2cb9334 commit f5fd592

6 files changed

Lines changed: 54 additions & 24 deletions

File tree

EfCore.BulkOperations.API/Repositories/ProductRepository.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ public async Task SyncDataThenCommit(List<Product> list1, List<Product> list2)
6464
transaction = await dbContext.Database.BeginTransactionAsync();
6565
var dbTransaction = transaction.GetDbTransaction();
6666

67-
await dbContext.BulkInsertAsync(list1, null, dbTransaction);
67+
await dbContext.BulkInsertAsync(
68+
list1,
69+
option =>
70+
{
71+
option.BatchSize = 1000;
72+
option.CommandTimeout = 60;
73+
},
74+
dbTransaction);
6875
await dbContext.BulkInsertAsync(list2, null, dbTransaction);
6976

7077
await transaction.CommitAsync();
@@ -91,7 +98,7 @@ public async Task SyncDataThenRollback(Product item1, List<Product> list2, List<
9198
transaction = await dbContext.Database.BeginTransactionAsync();
9299
var dbTransaction = transaction.GetDbTransaction();
93100

94-
dbContext.Products.Add(item1);
101+
await dbContext.Products.AddAsync(item1);
95102
await dbContext.SaveChangesAsync();
96103
await dbContext.BulkInsertAsync(list2, null, dbTransaction);
97104
await dbContext.BulkInsertAsync(list3, null, dbTransaction);

EfCore.BulkOperations/BulkOption.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,28 @@
22

33
namespace EfCore.BulkOperations;
44

5-
65
/// <summary>
76
/// The configurable options for bulk operations (insert/update) on entities using EfCoreBulkUtils.
87
/// </summary>
98
public class BulkOption<T>(
10-
int? batchSize = null,
11-
Expression<Func<T, object>>? ignoreOnInsert = null,
12-
Expression<Func<T, object>>? ignoreOnUpdate = null,
13-
Expression<Func<T, object>>? uniqueKeys = null
9+
int? batchSize = null,
10+
int? commandTimeout = null,
11+
Expression<Func<T, object>>? ignoreOnInsert = null,
12+
Expression<Func<T, object>>? ignoreOnUpdate = null,
13+
Expression<Func<T, object>>? uniqueKeys = null
1414
) where T : class
1515
{
1616
/// <summary>
1717
/// Gets or sets the batch size for bulk operations. Defaults to 200 if not specified.
1818
/// </summary>
1919
public int BatchSize { get; set; } = batchSize ?? 200;
2020

21+
/// <summary>
22+
/// Gets or sets the wait time (in seconds) before terminating the attempt to execute the command and generating an
23+
/// error.
24+
/// </summary>
25+
public int? CommandTimeout { get; set; } = commandTimeout;
26+
2127
/// <summary>
2228
/// Gets or sets an expression that identifies a property on the entity type `T` to be ignored during insert
2329
/// operations.

EfCore.BulkOperations/Docs/README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ await _dbContext.BulkInsertAsync(items);
2626
var items = new List<Product> { new Product("Product1", 100m) };
2727
await _dbContext.BulkInsertAsync(
2828
items,
29-
option => { option.IgnoreOnInsert = x => new { x.CreatedAt }; }
29+
option =>
30+
{
31+
option.BatchSize = 1000;
32+
option.CommandTimeout = 120;
33+
option.IgnoreOnInsert = x => new { x.CreatedAt };
34+
}
3035
);
3136
```
3237

@@ -102,7 +107,7 @@ try
102107
transaction = await dbContext.Database.BeginTransactionAsync();
103108
var dbTransaction = transaction.GetDbTransaction();
104109

105-
dbContext.Products.Add(item1);
110+
await dbContext.Products.AddAsync(item1);
106111
await dbContext.SaveChangesAsync();
107112
await dbContext.BulkInsertAsync(list2, null, dbTransaction);
108113
await dbContext.BulkInsertAsync(list3, null, dbTransaction);
@@ -118,4 +123,4 @@ finally
118123
{
119124
if (connection is { State: ConnectionState.Open }) await connection.CloseAsync();
120125
}
121-
```
126+
```

EfCore.BulkOperations/EfCore.BulkOperations.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010
<RepositoryUrl>https://github.com/hongjs/EfCore.BulkOperations</RepositoryUrl>
1111
<RepositoryType>github</RepositoryType>
1212
<PackageTags>BulkInsert,BulkUpdate,BulkDelete,BulkMerge</PackageTags>
13-
<Version>1.2.0</Version>
13+
<Version>1.3.0</Version>
1414
<PackageReadmeFile>README.md</PackageReadmeFile>
1515
<PackageProjectUrl>https://github.com/hongjs/EfCore.BulkOperations</PackageProjectUrl>
1616
<PackageLicenseUrl>https://github.com/hongjs/EfCore.BulkOperations?tab=MIT-1-ov-file</PackageLicenseUrl>
1717
</PropertyGroup>
1818

1919
<ItemGroup>
20-
<None Include="Docs\README.md" Pack="true" PackagePath="\" />
20+
<None Include="Docs\README.md" Pack="true" PackagePath="\"/>
2121
</ItemGroup>
2222
<ItemGroup>
23-
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
24-
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
23+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4"/>
24+
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4"/>
2525
</ItemGroup>
2626
</Project>

EfCore.BulkOperations/EfCoreBulkUtils.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
namespace EfCore.BulkOperations;
77

8-
98
/// <summary>
109
/// Provides a set of static methods for performing efficient bulk operations (insert, update, delete, merge)
1110
/// on entities using Entity Framework Core.
@@ -32,7 +31,7 @@ internal async static Task<int> BulkInsertAsync<T>(DbContext dbContext,
3231
optionFactory?.Invoke(option);
3332

3433
var batches = BulkCommand.GenerateInsertBatches(dbContext, items, option);
35-
await BulkExecuteAsync(dbContext, batches, transaction, cancellationToken);
34+
await BulkExecuteAsync(dbContext, batches, option.CommandTimeout, transaction, cancellationToken);
3635
return batches.Sum(x => x.SuccessCount) ?? 0;
3736
}
3837

@@ -56,7 +55,7 @@ internal async static Task<int> BulkUpdateAsync<T>(DbContext dbContext,
5655
optionFactory?.Invoke(option);
5756

5857
var batches = BulkCommand.GenerateUpdateBatches(dbContext, items, option);
59-
await BulkExecuteAsync(dbContext, batches, transaction, cancellationToken);
58+
await BulkExecuteAsync(dbContext, batches, option.CommandTimeout, transaction, cancellationToken);
6059
return batches.Sum(x => x.SuccessCount) ?? 0;
6160
}
6261

@@ -80,7 +79,7 @@ internal async static Task<int> BulkDeleteAsync<T>(DbContext dbContext,
8079
optionFactory?.Invoke(option);
8180

8281
var batches = BulkCommand.GenerateDeleteBatches(dbContext, items, option);
83-
await BulkExecuteAsync(dbContext, batches, transaction, cancellationToken);
82+
await BulkExecuteAsync(dbContext, batches, option.CommandTimeout, transaction, cancellationToken);
8483
return batches.Sum(x => x.SuccessCount) ?? 0;
8584
}
8685

@@ -106,7 +105,7 @@ internal async static Task<int> BulkMergeAsync<T>(DbContext dbContext,
106105
optionFactory?.Invoke(option);
107106

108107
var batches = BulkCommand.GenerateMergeBatches(dbContext, items, option);
109-
await BulkExecuteAsync(dbContext, batches, transaction, cancellationToken);
108+
await BulkExecuteAsync(dbContext, batches, option.CommandTimeout, transaction, cancellationToken);
110109
return batches.Sum(x => x.SuccessCount) ?? 0;
111110
}
112111

@@ -119,6 +118,7 @@ internal async static Task<int> BulkMergeAsync<T>(DbContext dbContext,
119118
private static async Task BulkExecuteAsync(
120119
DbContext dbContext,
121120
IEnumerable<BatchData> batches,
121+
int? commandTimeout = null,
122122
DbTransaction? externalTransaction = null,
123123
CancellationToken? cancellationToken = null)
124124
{
@@ -128,7 +128,7 @@ private static async Task BulkExecuteAsync(
128128
try
129129
{
130130
foreach (var batch in batches)
131-
await ExecuteBatchDataAsync(batch, connection, transaction, cancellationToken);
131+
await ExecuteBatchDataAsync(batch, connection, commandTimeout, transaction, cancellationToken);
132132

133133
if (externalTransaction is null) await transaction.CommitAsync(cancellationToken ?? default);
134134
}
@@ -150,16 +150,23 @@ private static async Task BulkExecuteAsync(
150150
/// <summary>
151151
/// Executes a single SQL batch asynchronously.
152152
/// </summary>
153+
/// <param name="batch">DbConnection</param>
154+
/// <param name="connection">DbConnection</param>
155+
/// <param name="commandTimeout">commandTimeout</param>
156+
/// <param name="dbTransaction">dbTransaction</param>
157+
/// <param name="cancellationToken">cancellationToken</param>
153158
private static async Task ExecuteBatchDataAsync(
154159
BatchData batch,
155160
DbConnection connection,
161+
int? commandTimeout,
156162
DbTransaction? dbTransaction,
157163
CancellationToken? cancellationToken = null)
158164
{
159165
await using var command = connection.CreateCommand();
160166
if (command.Connection is null) throw new ArgumentException("Command.Connection is null");
161167
if (dbTransaction is not null) command.Transaction = dbTransaction;
162168
command.CommandText = batch.Sql.ToString();
169+
if (commandTimeout is not null) command.CommandTimeout = commandTimeout.Value;
163170

164171
batch.Parameters.ToList().ForEach(p =>
165172
{

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ await _dbContext.BulkInsertAsync(items);
2626
var items = new List<Product> { new Product("Product1", 100m) };
2727
await _dbContext.BulkInsertAsync(
2828
items,
29-
option => { option.IgnoreOnInsert = x => new { x.CreatedAt }; }
29+
option =>
30+
{
31+
option.BatchSize = 1000;
32+
option.CommandTimeout = 120;
33+
option.IgnoreOnInsert = x => new { x.CreatedAt };
34+
}
3035
);
3136
```
3237

@@ -102,12 +107,12 @@ try
102107
transaction = await dbContext.Database.BeginTransactionAsync();
103108
var dbTransaction = transaction.GetDbTransaction();
104109

105-
dbContext.Products.Add(item1);
110+
await dbContext.Products.AddAsync (item1);
106111
await dbContext.SaveChangesAsync();
107112
await dbContext.BulkInsertAsync(list2, null, dbTransaction);
108113
await dbContext.BulkInsertAsync(list3, null, dbTransaction);
109114

110-
await transaction.CommitAsync();
115+
throw new DbUpdateException("Internal Server Error");
111116
}
112117
catch (Exception)
113118
{
@@ -118,4 +123,4 @@ finally
118123
{
119124
if (connection is { State: ConnectionState.Open }) await connection.CloseAsync();
120125
}
121-
```
126+
```

0 commit comments

Comments
 (0)