foreach 循环中的实体验证,如果验证失败,则在下一个循环中保持失败
Posted
技术标签:
【中文标题】foreach 循环中的实体验证,如果验证失败,则在下一个循环中保持失败【英文标题】:Entity validation in foreach loop, if validation fails it stays failed for next loop 【发布时间】:2012-06-03 15:35:22 【问题描述】:我遇到了一个奇怪的问题。我有一个包含现有项目的数据库,我添加了一个新的验证规则,因此数据库中的一些项目不符合这个新规则。
我有一个循环查找记录,更改元素然后将其保存回数据库,如下所示:
foreach(int foo in bar)
Model model = db.Model.Find(foo);
model.updated = true;
if(ModelState.IsValid)
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
我认为对于不符合新验证规则的记录将不会更新,因为 ModelState.IsValid
不会通过。但情况并非如此,它会引发验证失败异常。所以我把它放在try catch
中,然后我想我会记录错误,这样我就知道哪些记录无效。所以它现在看起来像这样:
foreach(int foo in bar)
Model model = db.Model.Find(foo);
model.updated = true;
try
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
catch(Exception x)
// log error
if(ModelState.IsValid)
db.ErrorLogs.Add(errorLog);
db.SaveChanges();
这也会引发验证失败异常,我猜是因为try
中的异常没有被清除。很好,我决定尝试一下,而不是发现错误。所以它看起来像这样:
foreach(int foo in bar)
Model model = db.Model.Find(foo);
model.updated = true;
try
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
catch()
现在最终发生的事情是说我有 100 条记录在 foreach 循环中循环,如果 #27 验证失败后的每条记录都失败了,因此不会更新!
这很严重,我该如何解决?有没有办法清除验证错误?为什么错误持续到所有其他循环?是因为db
在循环外声明了吗? 为什么它首先通过 ModelState.IsValid?
谢谢
【问题讨论】:
你检查过for
循环吗?
【参考方案1】:
我认为您将 ASP.NET MVC 验证与实体框架的验证混淆了。
ModelState.IsValid
检查绑定到 MVC 操作参数的模型的有效性。
实体框架会自行验证它尝试保存的实体。
您的模型中无效的方面似乎不是发送到您的操作方法的那些方面,而是来自数据库的那些方面。所以当模型绑定发生时,你有一个有效的对象,ModelState.IsValid
是真的。但是当您尝试保存对象时,Entity Framework 仍然会检测到它们无效并抛出异常。
您会在实体上创建导致数据库中当前数据不正确的验证,这似乎很奇怪。考虑运行 SQL 脚本来更正数据库中的数据。
如果您不能这样做,您可以在将实体加载出数据库后尝试绑定它们:
var models = db.Model.Where(f => bar.Contains(f.Id)).ToList();
TryUpdateModel(models);
if(ModelState.IsValid)
foreach(var model in models)
model.updated = true;
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
当然,上面的代码只有在模型的所有都有效的情况下才有效。如果您想选择性地只更新正确的条目,您可以检查ModelState.Errors
属性以了解与每个模型条目相关的错误。
如果您真的想在这种特殊情况下禁止实体验证,请记住这可能很危险,您可以在保存之前简单地禁用上下文验证。
db.Configuration.ValidateOnSaveEnabled = false;
【讨论】:
感谢您的信息,有没有办法改变实体的行为以不在此特定部分检查验证? @GarrettFogerlie:见***.com/questions/8099949/… 非常感谢,在保存更改之前添加db.Configuration.ValidateOnSaveEnabled = false;
效果很好。将此添加到您的答案中,我会接受。我无法更新现有数据库信息的原因是因为它是一个是或否的答案,同意从一开始就应该要求的条款。谢谢!以上是关于foreach 循环中的实体验证,如果验证失败,则在下一个循环中保持失败的主要内容,如果未能解决你的问题,请参考以下文章
如何在 foreach 循环中验证元素是不是在集合中的最后一个?