Skip to content

Commit 7d40a3d

Browse files
committed
SQLite: execute bulk operations within a transaction, otherwise SQLite will start a new transaction for every statement
1 parent 8eda61a commit 7d40a3d

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

src/Thinktecture.EntityFrameworkCore.Sqlite/EntityFrameworkCore/BulkOperations/SqliteBulkOperationExecutor.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public async Task<int> BulkUpdateAsync<T>(
153153
options.PropertiesToUpdate.DeterminePropertiesForUpdate(entityType, null),
154154
sqliteOptions.AutoIncrementBehavior);
155155
var tableName = entityType.GetTableName()
156-
?? throw new Exception($"The entity '{entityType.Name}' has no table name.");
156+
?? throw new Exception($"The entity '{entityType.Name}' has no table name.");
157157

158158
return await ExecuteBulkOperationAsync(entities, entityType.GetSchema(), tableName, ctx, cancellationToken);
159159
}
@@ -180,7 +180,7 @@ public async Task<int> BulkInsertOrUpdateAsync<T>(
180180
sqliteOptions.PropertiesToUpdate.DeterminePropertiesForUpdate(entityType, true),
181181
sqliteOptions.AutoIncrementBehavior);
182182
var tableName = entityType.GetTableName()
183-
?? throw new Exception($"The entity '{entityType.Name}' has no table name.");
183+
?? throw new Exception($"The entity '{entityType.Name}' has no table name.");
184184

185185
return await ExecuteBulkOperationAsync(entities, entityType.GetSchema(), tableName, ctx, cancellationToken);
186186
}
@@ -196,6 +196,11 @@ private async Task<int> ExecuteBulkOperationAsync<T>(
196196

197197
try
198198
{
199+
// Execute bulk operations within a transaction, otherwise SQLite will start a new transaction for every statement
200+
await using var tx = _ctx.Database.CurrentTransaction == null
201+
? await _ctx.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false)
202+
: null;
203+
199204
var tableIdentifier = _sqlGenerationHelper.DelimitIdentifier(tableName, schema);
200205

201206
using var reader = bulkOperationContext.CreateReader(entitiesOrValues);
@@ -207,6 +212,9 @@ private async Task<int> ExecuteBulkOperationAsync<T>(
207212
numberOfAffectedRows += await ExecuteBulkOperationForSeparatedOwnedEntitiesAsync((IReadOnlyList<object>)readEntities, bulkOperationContext, cancellationToken);
208213
}
209214

215+
if (tx is not null)
216+
await tx.CommitAsync(cancellationToken);
217+
210218
return numberOfAffectedRows;
211219
}
212220
finally
@@ -228,7 +236,7 @@ private async Task<int> ExecuteBulkOperationForSeparatedOwnedEntitiesAsync(
228236
foreach (var childContext in parentBulkOperationContext.GetChildren(parentEntities))
229237
{
230238
var childTableName = childContext.EntityType.GetTableName()
231-
?? throw new InvalidOperationException($"The entity '{childContext.EntityType.Name}' has no table name.");
239+
?? throw new InvalidOperationException($"The entity '{childContext.EntityType.Name}' has no table name.");
232240

233241
numberOfAffectedRows += await ExecuteBulkOperationAsync(childContext.Entities,
234242
childContext.EntityType.GetSchema(),
@@ -416,7 +424,7 @@ public async Task TruncateTableAsync(Type type, CancellationToken cancellationTo
416424
{
417425
var entityType = _ctx.Model.GetEntityType(type);
418426
var tableName = entityType.GetTableName()
419-
?? throw new InvalidOperationException($"The entity '{entityType.Name}' has no table name.");
427+
?? throw new InvalidOperationException($"The entity '{entityType.Name}' has no table name.");
420428

421429
var tableIdentifier = _sqlGenerationHelper.DelimitIdentifier(tableName, entityType.GetSchema());
422430
var truncateStatement = $"DELETE FROM {tableIdentifier};";

0 commit comments

Comments
 (0)