我的网站上有下一个代码(例如,SO的例子非常简化):
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
}
当SomeCalculations()
抛出异常时,order
对象处于不一致状态(其Status
为XOrderStatus.Completed
,但未设置CompletedOn
。 dataContext.SubmitChanges(); // 1
没有被调用,这里的一切都很好。但。你看到dataContext.SubmitChanges(); // 2
了吗?它被称为。与XExceptionEvent一起,它将order
的不需要的更改提交到我的数据库。
好。我尝试为异常创建另一个XDataContext
。但exceptionsDataContext.SubmitChanges();
表示currentUser
是通过不同的XDataContext
加载的。有任何想法吗?是否有任何优雅的方法可以取消order
的无效更改?
答案 0 :(得分:2)
您的TransactionScope
确保范围内的所有数据库操作都写入数据库,或者根本不写入。
它不会以任何方式影响内存中对象的更改,包括order
。
一个简单的解决方案是丢弃您当前使用的DataContext并实例化一个新的(假设可以放弃未保存的实体更改)。
对于其他选项,请查看相关的
How can I reject all changes in a Linq to SQL's DataContext?
,具体而言
http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext/
LINQ to SQL DataContext提供了出色的功能,可以管理对数据库的一组本地更改,只需调用SubmitChanges()即可将其推送到服务器。不可避免地会出现您想要丢弃所做更改的情况,从而有效地允许您继续使用DataContext,就好像这些更改从未进行过一样。不幸的是,没有DataContext.DiscardChanges()方法。一个小小的研究表明这是设计的,你应该简单地在这些情况下重新创建DataContext,但当然,没有什么是那么简单。现在,您需要重置来自原始DataContext的每个对象,以使用新对象来保证可预测的行为。