1

私は奇妙な問題を抱えています。既存のアイテムを含むデータベースがあり、新しい検証ルールを追加したため、データベース内の一部のアイテムがこの新しいルールに準拠していません。

次のように、レコードを見つけて要素を変更し、それをデータベースに保存するループがあります。

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()
    {
    }
}

何が起こっているかというと、foreach ループを循環する 100 レコードがあるとします。#27 が検証に失敗すると、その後のすべてのレコードが失敗し、更新されません!

これは非常に厄介です。どうすれば修正できますか? 検証エラーをクリアする方法はありますか? 他のすべてのループでエラーが続くのはなぜですか? dbループの外で宣言されたからですか?そもそも ModelState.IsValid を渡すのはなぜですか?

ありがとう

4

1 に答える 1

3

ASP.NET MVC の検証と Entity Framework の検証を混同していると思います。

  • ModelState.IsValidMVC アクションのパラメーターにバインドされたモデルの有効性をチェックします。
  • Entity Framework は、保存しようとするエンティティの独自の検証を行います。

有効でないモデルの側面は、アクション メソッドに送信された側面ではなく、データベースから出てきた側面のようです。したがって、モデル バインディングが発生したとき、有効なオブジェクトがあり、それModelState.IsValidは true です。ただし、オブジェクトを保存しようとすると、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;
于 2012-06-03T15:43:38.950 に答える