Reputation: 4425
I had implemented an ActionFilter, that logs all my actions to a table.
My current approach:
using (var scope = context.Database.BeginTransaction())
{
try
{
//some code
context.SaveChanges();
scope.Commit();
}
catch (Exception ex)
{
scope.Rollback();
throw ex;
}
}
...
dbSet.Add(mylog);
context.SaveChanges();
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
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
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