using System; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Storage; namespace Microsoft.EntityFrameworkCore { /// /// Extensions for the . /// public static class DbContextExensions { /// /// Starts a new transaction. /// /// /// See Transactions in EF Core for more information. /// /// The current . /// /// A that represents the started transaction. /// public static IDbContextTransaction BeginTransaction(this DbContext dbContext) { if (dbContext.Database.GetProviderType() == DatabaseFacadeExtensions.DatabaseProvider.InMemory) return new DbContextTransactionStub(); return dbContext.Database.BeginTransaction(); } /// /// Asynchronously starts a new transaction. /// /// /// /// Entity Framework Core does not support multiple parallel operations being run on the same DbContext instance. This /// includes both parallel execution of async queries and any explicit concurrent use from multiple threads. /// Therefore, always await async calls immediately, or use separate DbContext instances for operations that execute /// in parallel. See Avoiding DbContext threading issues /// for more information. /// /// /// See Transactions in EF Core for more information. /// /// /// The current . /// A to observe while waiting for the task to complete. /// /// A task that represents the asynchronous transaction initialization. The task result contains a that represents the started transaction. /// /// If the is canceled. public static Task BeginTransactionAsync(this DbContext dbContext, CancellationToken cancellationToken) { if (dbContext.Database.GetProviderType() == DatabaseFacadeExtensions.DatabaseProvider.InMemory) return Task.FromResult(new DbContextTransactionStub()); return dbContext.Database.BeginTransactionAsync(cancellationToken); } /// private class DbContextTransactionStub : IDbContextTransaction { /// public Guid TransactionId { get; private set; } = Guid.NewGuid(); /// public void Commit() { } /// public Task CommitAsync(CancellationToken cancellationToken = default) => Task.CompletedTask; /// public void Dispose() { } /// public ValueTask DisposeAsync() => new(Task.CompletedTask); /// public void Rollback() { } /// public Task RollbackAsync(CancellationToken cancellationToken = default) => Task.CompletedTask; } } }