Denis
Denis

Reputation: 3757

DataContext.SubmitChanges() submits unwanted data

I have the next code in my website (example is very-very simplified for SO, of course):

XDataContext dataContext = new XDataContext();
int currentUserId = GetCurrentUserIdFromSession();
XUser currentUser = dataContext.Users.Single(u => u.Id == currentUserId);

try
{
    using (var t = new TransactionScope())
    {
        int orderId = GetOrderIdFromSession();
        XOrder order = dataContext.Orders.Single(o => o.Id == orderId);
        order.Status = XOrderStatus.Completed;
        order.TransactionId = SomeCalculations(); // exception here
        order.CompletedOn = DateTime.UtcNow;
        dataContext.SubmitChanges(); // 1
        t.Complete();
    }
}
catch (Exception ex)
{
    XExceptionEvent exceptionEvent = new XExceptionEvent();
    exceptionEvent.User = currentUser;
    dataContext.ExceptionEvents.InsertOnSubmit(exceptionEvent);
    dataContext.SubmitChanges(); // 2
}

When SomeCalculations() throws an exception, order object is in inconsistent state (its Status is XOrderStatus.Completed, but CompletedOn is not set). dataContext.SubmitChanges(); // 1 is not called, everything is good here. BUT. Do you see dataContext.SubmitChanges(); // 2. It is called. And along with XExceptionEvent, it submits unwanted changes of order to my database.

Okay. I tried to create another XDataContext for exceptions. But exceptionsDataContext.SubmitChanges(); says that currentUser is loaded through different XDataContext. Any ideas? Is there any elegant way to cancel non-valid changes of my order?

Upvotes: 0

Views: 493

Answers (1)

Eric J.
Eric J.

Reputation: 150198

Your TransactionScope ensures that all database actions within the scope are written to the database, or none at all.

It does not in any way affect changes to an object in memory, including order.

One simple solution would be to discard the DataContext you are currently working with and instantiate a new one (assuming it is OK to discard the unsaved changes to the entity).

For other options, have a look at the related

How can I reject all changes in a Linq to SQL's DataContext?

and specifically

http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext/

The LINQ to SQL DataContext provides excellent functionality for managing a set of local changes to a database that can be pushed to the server with a single call to SubmitChanges(). Inevitably there will be situations where you want to discard the changes you have made, effectively allowing you to continue using the DataContext as though those changes had never been made. Unfortunately, there is no DataContext.DiscardChanges() method. A little research reveals that this is by design and that you should simply recreate the DataContext in these cases, but of course, nothing is that simple. Every object you have that came from the original DataContext now needs to be reset to use the new one to guarantee predictable behaviour.

Upvotes: 2

Related Questions