foreach循环中的实体验证,如果验证失败,则下一循环保持失败

时间:2012-06-03 15:35:23

标签: c# entity-framework validation model

我有一个奇怪的问题。我有一个包含现有项目的数据库,我添加了一个新的验证规则,因此数据库中的某些项目不符合这个新规则。

我有一个循环找到一条记录,更改一个元素然后将其保存回数据库,如下所示:

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?

由于

1 个答案:

答案 0 :(得分:3)

我认为您将ASP.NET MVC验证与Entity Framework的验证混淆。

  • ModelState.IsValid检查绑定到MVC Action参数的模型的有效性。
  • 实体框架对其尝试保存的实体进行自己的验证。

模型中无效的方面似乎不是那些发送到您的操作方法的方面,而是那些来自数据库的方面。因此,当模型绑定发生时,您有一个有效的对象,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();
}

当然,只有模型的 all 有效时,上述代码才有效。如果要有选择地仅更新正确的属性,可以检查ModelState.Errors属性是否存在与每个模型条目相关的错误。

如果你真的想在这种特殊情况下抑制实体验证,请记住这可能是危险的,你可以在保存前简单地禁用上下文验证。

db.Configuration.ValidateOnSaveEnabled = false;