23

DbContext および POCO エンティティで Entity Framework 5.0 を使用しています。3 つのプロパティを含む単純なエンティティがあります。

public class Record
{
    public int Id { get; set; }
    public string Title { get; set; }
    public bool IsActive { get; set; }
}

Title フィールドは常に変更されず、UI は変更するための入力ボックスを提供せずに単に表示します。そのため、フォームがサーバーに送信されるときにTitleフィールドが に設定されます。null

エンティティの部分的な更新を実行するように EF に指示する方法は次のIsActiveとおりです (フィールドのみ)。

public class EFRepository<TEntity>
{
   ...
   public void PartialUpdate(TEntity entity, params Expression<Func<TEntity, object>>[] propsToUpdate)
   {
       dbSet.Attach(entity);
       var entry = _dbContext.Entry(entity);
       foreach(var prop in propsToUpdate)
           contextEntry.Property(prop).IsModified = true;
   }
}

そして呼び出し:

repository.PartialUpdate(updatedRecord, r => r.IsActive);

SaveChangesメソッドを呼び出すDbEntityValidationExceptionと、Titleが必要であることがわかります。を設定するとdbContext.Configuration.ValidateOnSaveEnabled = false、すべて問題ありません。コンテキスト全体で検証を無効にすることを回避し、更新されていないプロパティを検証しないように EF に指示する方法はありますか? 前もって感謝します。

4

3 に答える 3

25

部分的な更新またはスタブ エンティティを使用する場合 (どちらのアプローチもかなり有効です!) 、部分的な変更を尊重しないため、グローバル EF 検証を使用できません。常にエンティティ全体を検証します。デフォルトの検証ロジックでは、前述の呼び出しによってオフにする必要があります。

dbContext.Configuration.ValidateOnSaveEnabled = false

そして、更新されたすべてのプロパティを個別に検証します。これでうまくいくはずですが、EF検証をまったく使用していないため、試しませんでした。

foreach(var prop in propsToUpdate) {
    var errors = contextEntry.Property(prop).GetValidationErrors();
    if (erros.Count == 0) {
        contextEntry.Property(prop).IsModified = true;
    } else {
        ...
    }
}

さらに先に進みたい場合ValidateEntityは、コンテキストでオーバーライドして、エンティティ全体またはエンティティの状態とプロパティの状態に基づいて選択したプロパティのみを検証する方法で検証を再実装するIsModifiedことができます。これにより、部分的な更新で EF 検証を使用できるようになります。およびスタブ エンティティ。

EF での検証は、IMHO の間違った概念です。ロジックが属していないデータ アクセス レイヤーに追加のロジックが導入されます。これは主に、ナビゲーション プロパティに必要な検証規則を配置する場合、エンティティ全体またはエンティティ グラフ全体を常に操作するという考えに基づいています。このアプローチに違反すると、エンティティにハードコードされた単一の固定された検証ルールのセットでは不十分であることが常にわかります。

非常に長いバックログの 1 つは、検証が操作速度にどのように影響するかを調査することですSaveChanges。以前は、DataAnnotations とそのクラスに基づいて EF4 (EF4.1 より前) に独自の検証 API を使用していましたが、Validatorすぐに使用をやめました。パフォーマンスが非常に悪いためです。

ネイティブ SQL を使用した回避策は、検証をオフにしてスタブ エンティティまたは部分更新を使用した場合と同じ効果があります。つまり、エンティティはまだ検証されていませんが、変更は同じ作業単位の一部ではありません。

于 2012-10-14T08:00:48.310 に答える
20

Ladislav's answerを参照して、これをDbContextクラスに追加しました。変更されていないすべてのプロパティが削除されます。
これらのプロパティの検証を完全にスキップするのではなく、単に省略していることはわかっていますが、EF はプロパティではなくエンティティごとに検証し、検証プロセス全体を新たに書き直すのは面倒でした。

protected override DbEntityValidationResult ValidateEntity(
  DbEntityEntry entityEntry,
  IDictionary<object, object> items)
{
  var result = base.ValidateEntity(entityEntry, items);
  var falseErrors = result.ValidationErrors
    .Where(error =>
    {
      if (entityEntry.State != EntityState.Modified) return false;
      var member = entityEntry.Member(error.PropertyName);
      var property = member as DbPropertyEntry;
      if (property != null)
        return !property.IsModified;
      else
        return false;//not false err;
    });

  foreach (var error in falseErrors.ToArray())
    result.ValidationErrors.Remove(error);
  return result;
}
于 2015-04-17T03:21:31.487 に答える