How to rollback data changes in DBContext if 'SubmitChanges' failed but other submits are required?
In some business cases my app I have error cause inside of transaction. Situation looks like this:
static void MyFunc(DBContext context)
{
context.MyObjects.InsertOnSubmit(new MyObj{Id=1});
// Id - is a primary key
context.MyObjects.InsertOnSubmit(new MyObj{Id=1});
// here I force system to fail
// by trying to add record with
// duplicated primary key value
context.SubmitChanges(); // causes an error (as expected)
}
static void main()
{
using (DBContext context = new DBContext())
{
try
{
using (TransactionScope scope = CreateTransactionScope())
{
MyFunc(context);
scope.Complete();
}
}
catch(Exception exc)
{
MyLog log = new MyLog{...valid object data... want to log error ... };
context.MyLogs.InsertOnSubmit(log);
context.SubmitChanges();
}
}
}
the problem here is that attempt to save 'log' object causes attempt to save previously added objects into 'MyObject' table too! And as a result I can't save log record... and my 'main' function throws an exception...
How could I resolve that? Any thoughts are welcome.
(I'm using MS SQL 2005, Linq2Sql, .NET 3.5, ideas for .NET 4.0 are also welcome!)
P.S. I know it could be a good idea to call 'scope.Rollback', but if I leave 'using (TransactionScope scope ...)' without calling 'Complete' then 'Rollback should be applied automatically...
P.P.S. I could create a new 'DBContext' object, but don开发者_StackOverflow社区't think it is reasonable.
A transaction is a tool to group actions that must be performed as a whole, not in parts. Since you have some actions that can (and in your case must) be easily separated from the rest, it seems a lot more appropriate to use two separate transactions.
Generally speaking, the DataContext will keep a reference to all the objects that were loaded from or attached to it in memory. I could be wrong, but I do not believe the changes within the TransactionScope are rolled back in the "in-memory" objects.
Therefore SubmitChanges() on the context in the error handler will try to resubmit all the changes to the "in-memory" model. The only way I know of to correct this is to reset the "in-memory" model by creating a new context.
you can rollback in context like this
public void Rollback()
{
base.ChangeTracker.Entries().ToList().ForEach(entry => entry.State = System.Data.EntityState.Unchanged);
}
精彩评论