Reputation: 3
I'm having Issues with entity framework using transactions and ASP MVC, for example, if at some point during the transaction an exception is thrown, the DbContext remains outdated because the rollback did not return the navigation collection to its original state.
Entity Framework version: 6.1
Related model:
public Action {
public int Id;
public string property;
}
Main Model:
public Model1 {
public int Id;
public virtual ICollection<Action> Actions
}
and the try/catch block to rollback
//There is only one instance of DbContext, and is shared with all controllers and models
DbContext context = GetSingletonContext();
DbContextTransaction transaction = context.Database.BeginTransaction();
Model1 instance = null;
try
{
instance = context.Model1.Find(31);
instance.Actions.Remove(instance.Actions.First());
throw new ExceptionOfAnyKind();
context.SaveChanges();
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
throw;
}
I did something like this to 'clear' the entity tracker, so the next time Entity Framework theorically will use the database, but i'm not sure if this can lead to some kind of issues in other actions of controllers that should be being used at the same time:
var entities = (from entity in entityManager.ChangeTracker.Entries() select entity).ToList();
foreach (var item in entities)
{
item.State = EntityState.Detached;
}
My question is, how can i ensure that even when an error is thrown, the DbContext is always updated or returned to the previous state, or if there is a way to force the reload of navigation collections of a single model instance.
already tried this:
var entry = context.Entry<Model1>(instance).Collection("Actions");
entry.IsLoaded = false;
entry.Load();
and this one just reload properties of the model, but no the navigation properties
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
objectContext.Refresh(RefreshMode.StoreWins, instance);
same as previous:
var entry = context.Entry<Model1>(instance);
entry.Reload();
When using AsNoTracking, the instance has the correct values, but cannot be updated or deleted until attached to the context, and if already an entity with the same PK an exception is thrown
Upvotes: 0
Views: 2978
Reputation: 2107
You can use code transactions, instead of database transactions. And using using statements to dispose of dbcontext.
using (TransactionScope scope = new TransactionScope())
{
using (MyDBContext db = new MyDBContext())
{
//...
db.SaveChanges()
}
scope.Complete();
}
using (MyDBContext db = new MyDBContext())
{
//...
db.SaveChanges()
}
scope.Complete();
}
/* end of adding transaction scope*/
}
Upvotes: 1