false
传递给SaveChanges()
,然后在没有错误的情况下致电AcceptAllChanges()
,它们似乎就会在EF中照顾自己:SaveChanges(false);
// ...
AcceptAllChanges();
如果出现问题怎么办?
在事务中途分配的所有intentiy列会发生什么情况?我想如果有人在我的坏事发生之前在我的事后添加了一条记录,那么这意味着将丢失一个Identity值。
是否有任何理由在我的代码中使用标准
TransactionScope
类?#1 楼
使用实体框架,大多数时候SaveChanges()
就足够了。这将创建一个事务,或加入任何环境事务,并在该事务中完成所有必要的工作。因为这是您要在两个不同的上下文中进行分布式事务的情况。即像这样(不好):
using (TransactionScope scope = new TransactionScope())
{
//Do something with context1
//Do something with context2
//Save and discard changes
context1.SaveChanges();
//Save and discard changes
context2.SaveChanges();
//if we get here things are looking good.
scope.Complete();
}
如果
SaveChanges(false) + AcceptAllChanges()
成功但context1.SaveChanges()
失败,则整个分布式事务都将中止。但是不幸的是,实体框架已经放弃了对context2.SaveChanges()
的更改,因此您无法重播或有效地记录故障。但是如果将代码更改为如下所示:
using (TransactionScope scope = new TransactionScope())
{
//Do something with context1
//Do something with context2
//Save Changes but don't discard yet
context1.SaveChanges(false);
//Save Changes but don't discard yet
context2.SaveChanges(false);
//if we get here things are looking good.
scope.Complete();
context1.AcceptAllChanges();
context2.AcceptAllChanges();
}
尽管对
context1
的调用将必要的命令发送到数据库,但上下文本身未更改,因此您可以在必要时再次进行操作,也可以根据需要查询SaveChanges(false)
。 这意味着,如果事务实际上引发异常,则可以通过在某处重新尝试或记录每个上下文的状态来进行补偿。
评论
太好了,谢谢...因此,如果出现故障,我不必回滚吗? SaveChanges,将其标记为已保存,但是直到我接受allallchanges才真正提交。.但是如果出现问题..我将需要回滚,这样我的对象才能返回到正确的状态吗?
–马克·史密斯
09年5月10日在19:32
@Mark:如果通过“回滚”表示将对象恢复为它们在数据库中的状态,则不会,因为您将丢失所有用户对对象的更改,因此您不想这样做。 SaveChanges(false)对数据库进行实际更新,而AcceptAllChanges()告诉EF:“好的,您可以忘记需要保存哪些内容,因为它们已成功保存。”如果SaveChanges(false)失败,则将永远不会调用AcceptAllChanges(),并且EF仍将您的对象视为具有已更改的属性,需要将其保存回数据库。
– BlueRaja-Danny Pflughoeft
2010年3月29日15:22
您能建议使用Code First做到这一点吗? SaveChanges或AcceptAllChanges方法没有参数
–克尔斯滕·格里德(Kirsten Greed)
13年2月17日在5:44
我在这里问了一个关于将这种技术与Code First结合使用的问题
–克尔斯滕·格里德(Kirsten Greed)
13年2月18日在21:47
在EF 6.1中不再可能。您知道现在需要进行哪些调整才能工作吗?
– Alex Dresko
2014年7月24日在22:44
#2 楼
如果您使用的是EF6(Entity Framework 6+),则此更改已更改为对SQL的数据库调用。请参阅:http://msdn.microsoft.com/zh-cn/data/dn456843.aspx
使用context.Database.BeginTransaction。
来自MSDN:
using (var context = new BloggingContext())
{
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
context.Database.ExecuteSqlCommand(
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'"
);
var query = context.Posts.Where(p => p.Blog.Rating >= 5);
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context.SaveChanges();
dbContextTransaction.Commit();
}
catch (Exception)
{
dbContextTransaction.Rollback(); //Required according to MSDN article
throw; //Not in MSDN article, but recommended so the exception still bubbles up
}
}
}
评论
在事务上使用“使用”时,不需要使用回滚的try-catch。
–罗伯特
2014年11月6日上午10:41
我正在捕获这样的异常。它导致数据库操作静默失败。由于SO的性质,有人可能会举这个例子并在生产应用程序中使用它。
– B2K
15年7月27日在14:32
@ B2K:很好,但是此代码是从链接的Microsoft文章中复制的。我希望没有人在生产中使用他们的代码:)
– J布赖恩·普莱斯(J Bryan Price)
2015年8月1日在20:18
@Robert根据MSDN文章Rollback()是必需的。他们故意为TransactionScope示例省略了“回滚”命令。我添加了@ B2K;到MSDN代码段,并清楚地表明它不是MSDN文章中的原始内容。
–托德
16-4-3在12:41
(如果正确)这可能会解决问题:听起来像EF + MSSQL不需要回滚,但是EF +其他SQL提供程序可能需要。由于EF应该与它正在与哪个数据库无关,所以在与MySql或没有自动行为的情况下调用Rollback()。
–讨厌
16 Jun 13'20:52
#3 楼
因为某些数据库可以在dbContextTransaction.Commit()处引发异常,所以更好的方法是:using (var context = new BloggingContext())
{
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
context.Database.ExecuteSqlCommand(
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'"
);
var query = context.Posts.Where(p => p.Blog.Rating >= 5);
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context.SaveChanges(false);
dbContextTransaction.Commit();
context.AcceptAllChanges();
}
catch (Exception)
{
dbContextTransaction.Rollback();
}
}
}
评论
我正在捕获这样的异常。它导致数据库操作静默失败。由于SO的性质,有人可能会举这个例子并在生产应用程序中使用它。
– B2K
15年7月27日在14:32
这与其他引用归因于其引用的MSDN页面的答案是否基本相同?我看到的唯一区别是,您将false传递给context.SaveChanges();,并另外调用context.AcceptAllChanges();。
–李慧霞
2015年12月7日12:12
@ B2K不需要回滚-如果事务不起作用,则不会提交任何内容。同样,显式调用回滚可能会失败-在此处查看我的答案stackoverflow.com/questions/41385740/…
–肯
18-10-10在0:42
回滚不是我反对的目标。答案的作者更新了他们的代码以重新抛出异常,从而解决了我反对的问题。
– B2K
18-10-11在3:54
抱歉,我用手机发表了评论。 Todd重新引发异常,eMeL不会。捕获中应该有一些东西可以通知开发人员或用户导致回滚的问题。那可能是写入日志文件,重新抛出异常或向用户返回消息。
– B2K
18-10-12在15:06
评论
这帮助我了解了为什么SaveChanges(fase); ... AcceptAllChanges();首先是一种模式。请注意,博客作者是如何回答上述问题的,答案是另一个问题。全部都聚在一起。