2

I'm using MySQL with EF Core. I am currently using Pomelo Provider for MySQL. I need to implement Unit Of Work Pattern for transactions. I have a Service which calls two methods in repository. I am not able to implement nested transactions. This is how my method in service looks now:

    public void methodA(param)
    {
      using (TransactionScope tx = new 
        TransactionScope(TransactionScopeOption.Required))
        {
          repo1.save(data1);
          repo2.save(data2);
          tx.complete();
        }
    }

This is how save method in repo1 is implemented

    private readonly UserDbContext appDbContext;
    public repo1(UserDbContext _appDbContext)
    {
        appDbContext = _appDbContext;
    }
    public void save(User entity)
    {
        var dbset = appDbContext.Set<User>().Add(entity);
        appDbContext.SaveChanges();
    }

This is how save method in repo2 is implemented

    private readonly UserDbContext appDbContext;
    public repo2(UserDbContext _appDbContext)
    {
        appDbContext = _appDbContext;
    }
    public void save(UserRole entity)
    {
        var dbset = appDbContext.Set<UserRole>().Add(entity);
        appDbContext.SaveChanges();
    }

I am getting the following error while running method in service:

Error generated for warning 'Microsoft.EntityFrameworkCore.Database.Transaction.AmbientTransactionWarning: An ambient transaction has been detected. The current provider does not support ambient transactions. See http://go.microsoft.com/fwlink/?LinkId=800142'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.AmbientTransactionWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.

This is how I registered UserDbContext in Startup.cs

    services.AddDbContext<UserDbContext>(options => options.UseLazyLoadingProxies().UseMySql("Server = xxxx; Database = xxx; Uid = xx;ConnectionReset=True;", b => b.MigrationsAssembly("AssemblyName")));

I even tried adding a middleware which starts transaction at the begining of request and commits/rollbacks during the response . But still I am not able to manage nested transactions.

This is how my middleware looks:

    public class TransactionPerRequestMiddleware
    {
       private readonly RequestDelegate next_;

       public TransactionPerRequestMiddleware(RequestDelegate next)
        {
         next_ = next;
        }

       public async Task Invoke(HttpContext context, UserDbContext 
        userDbContext)
        {
           var transaction = userDbContext.Database.BeginTransaction(
           System.Data.IsolationLevel.ReadCommitted);

           await next_.Invoke(context);

           int statusCode = context.Response.StatusCode;
           if (statusCode == 200 || statusCode==302)
            {
            transaction.Commit();
            }
            else
            {
            transaction.Rollback();
            }
        }
     }

Can anyone help me please?

Dot Net developer
  • 436
  • 1
  • 5
  • 19
  • Repeating the same question won't get a different answer. Database transactions are *not* Units of Work. `TransactionScope` implements database transactions, not UoW. The middleware is still buggy and won't handle exceptions – Panagiotis Kanavos Jan 04 '19 at 12:31
  • Possible duplicate of [Transaction Per Request Middleware Not working](https://stackoverflow.com/questions/54035873/transaction-per-request-middleware-not-working) – Panagiotis Kanavos Jan 04 '19 at 12:32
  • Besides, if the database doesn't support nested transactions you can't fake them with TransactionScope or calls to BeginTransaction. Neither MySQL nor SQL Server support nested transactions. – Panagiotis Kanavos Jan 04 '19 at 12:35
  • To fix your current code, *remove* `SaveChanges` from the repo.save methods and call it in `MethodA`. Again, `SaveChanges` itself uses an internal transaction so you *don't* need TransactionScope or BeginTransaction – Panagiotis Kanavos Jan 04 '19 at 12:36
  • The workaround in MySQL and SQL Server is to [use savepoints](https://stackoverflow.com/questions/1306869/are-nested-transactions-allowed-in-mysql). Again, that's *not* needed to implement UoW, and is almost never used in web applications. Nested transactions and savepoints are needed when one has a really long script to run and wants to commit or rollback individual parts. – Panagiotis Kanavos Jan 04 '19 at 12:41

0 Answers0