Beetlejuice
Beetlejuice

Reputation: 4425

Controlling Transactions in Asp.Net core + EF Core

I had implemented an ActionFilter, that logs all my actions to a table.

My current approach:

Action

using (var scope = context.Database.BeginTransaction())
{
   try
   {
       //some code
       context.SaveChanges();
       scope.Commit();  
   }
   catch (Exception ex)
   {
      scope.Rollback();
      throw ex; 
   }
}

Filter

...
dbSet.Add(mylog);
context.SaveChanges();

Problem

When any error occurs inside "some code" in action, the entities changed inside this code will be saved to database when ActionFilter executes its "SaveChanges". So, the Rollback is doing nothing.

How make ActionFilter "see" only changes for entities it changes?

WHat's the best approach?

Upvotes: 1

Views: 557

Answers (2)

Steve Py
Steve Py

Reputation: 35063

If the changes done by the action filter are to be isolated without committing changes outside of it's scope or getting committed by SaveChanges out of its scope then I would suggest a bounded context for the Filter rather than relying on the common injected DbContext. For example an ActionFilterDbContext which registers just the entity definitions you need, and can simplify them to just the relationships etc. that the filter needs. If needed, a transaction scope can link persist operations across the two DbContexts.

The caveat being that the action filter DbContext will not see the modified state of entities on the app DbContext, nor will the main DbContext see modified state from the ActionFilterDbContext entities. So a filter for something like Logging might insert or update a Log entry, but if the filter wants to retrieve an entity it will not see the modified state from the app DbContext. (unless you also have a reference to that DbContext to fetch entities) Likewise, if the main application is reading log entries it may not "see" changes made by the bounded filter DbContext unless the data is refreshed from the DB. For web applications where DbContexts are scoped per-request anyways, this generally is not an issue since the DbContexts are relatively short-lived.

Upvotes: 1

David Browne - Microsoft
David Browne - Microsoft

Reputation: 89424

After a rollback the DbContext ChangeTracker is in the same state it was before .SaveChanges(). It's up to you to decide whether you can retry .SaveChanges() after the exception and rollback. If you want to discard the changes in the ChangeTracker without Disposing the DbContext, call

db.ChangeTracker.Clear();

Upvotes: 1

Related Questions