开发者

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);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜