Reputation: 3757
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
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