using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.Transactions;
public static async Task Main()
using var context = Helper.GenerateDbContext();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var svcB = new ServiceB(context, false);
var svcA = new ServiceA(context, svcB);
await svcA.Save(new ClassA());
Console.WriteLine("\n----------======== Caught! ========----------\n");
public static async Task Write(MyDbContext context)
Console.WriteLine("----------======== Write context! ========----------");
var listOfA = await context.As.ToListAsync();
var listOfB = await context.Bs.ToListAsync();
foreach (var a in listOfA)
Console.WriteLine($"a: {a.Id}");
foreach (var b in listOfB)
Console.WriteLine($"b: {b.Id}");
Console.WriteLine("----------======== Done! ========----------");
private readonly MyDbContext _dbContext;
private readonly IServiceB _serviceB;
public ServiceA(MyDbContext dbContext, IServiceB serviceB)
public async Task Save(ClassA a)
using var transaction = await _dbContext.Database.BeginTransactionAsync();
_dbContext.Add(new ClassA { Id = b.Id + 100 });
await _dbContext.SaveChangesAsync(CancellationToken.None);
await transaction.CommitAsync();
await transaction.RollbackAsync();
public class ServiceB : IServiceB
private readonly MyDbContext _dbContext;
private readonly bool _throwException;
public ServiceB(MyDbContext dbContext, bool throwException)
_throwException = throwException;
public async Task Save(ClassB b)
await _dbContext.SaveChangesAsync(CancellationToken.None);
throw new Exception("ServiceB.Save() induced exception!");
public interface IServiceB
public class MyDbContext : DbContext
public MyDbContext(DbContextOptions options) : base(options)
public DbSet<ClassA> As { get; set; }
public DbSet<ClassB> Bs { get; set; }
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
return await base.SaveChangesAsync(cancellationToken);
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
public int Id { get; set; }
public int Id { get; set; }
public static class Helper
public static MyDbContext GenerateDbContext()
var connection = new Microsoft.Data.Sqlite.SqliteConnection("Filename=:memory:");
var contextOptions = new DbContextOptionsBuilder<MyDbContext>().UseSqlite(connection).Options;
return new MyDbContext(contextOptions);