我有一个看起来像这样的循环:
CountsToReport = rep.Counts_Get().Where(x => x.Status == "Completed");
foreach (var count in CountsToReport.ToList())
{
//do some stuff
//send an email
count.Status = "Reported";
rep.SaveChanges();
}
其中" rep"是EF上下文的存储库包装器。
当这种情况发生时,不幸的电子邮件收件人会被垃圾邮件淹没,因为SaveChanges调用并未真正提交更改 - 因此循环会保持相同的计数,通过电子邮件发送,并将其标记为"报告& #34;但实际上并没有保存更改。
如果停止循环并重新启动代码,则更改会成功保存。您可以通过逐步执行代码来确认此方案:C#中的EF对象更改其状态,但SQL中的基础数据不会更改。
我认为这是因为SaveChanges实际上并没有提交事务 - 它只是将数据标记为已经为事务结束做好了准备。但是我们并没有在数据库中的任何其他位置使用事务,而且更改这个用例的存储库会有点麻烦。
有没有其他方法可以强制EF提交此更改并逃避无尽的厄运循环?或者我错了原因?
编辑:将其放入存储库并调用它而不是SaveChanges他修复了它:
public void SaveWithTransaction()
{
using (var transaction = new System.Transactions.TransactionScope())
{
db.SaveChanges();
transaction.Complete();
}
}
但它看起来很难看。仍然有兴趣知道是否还有另一种方式。
编辑:这是骗人的。看起来它只是旧的添加/修改问题了。将对象标记为已修改似乎有所帮助。
答案 0 :(得分:1)
很可能CountsToReport中的实体与上下文分离。 因此,不仅ChangeTracker没有看到对Count做出的任何改变,它根本不了解该实体。
解决问题:
db.Counts.Attach(count)
foreach (var count in CountsToReport.ToList())
{
//do some stuff
//send an email
rep.Counts.Attach(count);
count.Status = "Reported";
rep.SaveChanges();
}
有关实体状态以及如何处理它们的更多信息,请查看以下链接: http://msdn.microsoft.com/en-us/data/jj592676.aspx