EntityKeyおよびApplyPropertyChanges()

.net asp.net-mvc c# entity-framework

質問

EntityObjectのEntityKeyを設定する必要があります。私はその種類とそのid値を知っています。不必要にデータベースに問い合わせたくありません。

これは動作します...

//
// POST: /Department/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    Model.EntityKey = (from Department d in db.Department
                       where d.Id == id
                       select d).FirstOrDefault().EntityKey;
    db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
    db.SaveChanges();
    return RedirectToAction("Index");
}

これは失敗します...

//
// POST: /Department/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
    String EntitySetName = db.DefaultContainerName + "." + Model.GetType().Name;
    Model.EntityKey = new System.Data.EntityKey(EntitySetName, "Id", Model.Id);
    db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
    db.SaveChanges();
    return RedirectToAction("Index");
}

ApplyPropertyChanges()行はこの例外で失敗します。

ObjectStateManagerは、タイプ 'Sample.Models.Department'のオブジェクトへの参照を持つObjectStateEntryを含みません。

2つのEntityKeysは同じです。 2番目のコードブロックが失敗するのはなぜですか?どうすれば修正できますか?

人気のある回答

2番目のコードブロックが失敗するのは、EFがObjectStateManagerでオブジェクトを見つけることができないためです。つまり、dbからオブジェクトを取得すると、状態マネージャにそれらを追跡できるように配置します。これは、 Identity Mapパターンに似ています。 EntityKeyを持っていても、あなたのオブジェクトは状態マネージャにはないので、EFは変更を永続化することができません。あなたはオブジェクトをあなた自身でステートマネージャに入れることによってこれを回避することができますが、あなたはそれについて少し卑劣です。

これは動作します:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department model)
{
  var entitySetName = db.DefaultContainerName + "." + model.GetType().Name;
  var entityKey = new System.Data.EntityKey(entitySetName, "Id", model.Id);

  db.Attach(new Department{Id = id, EntityKey = entityKey});
  db.AcceptAllChanges();

  db.ApplyPropertyChanges(entitySetName, model);
  db.SaveChanges();
}

…でも、それほどきれいではありません。基本的にこれはエンティティキーだけで '空の'オブジェクトをアタッチし、すべての変更を受け入れてから実際に更新された実際の値でApplyPropertyChangesを呼び出します。

これは拡張メソッドでまとめたものと同じです。これは、主キーに単一のdb列を使用しているものすべてに有効です。このメソッドを呼び出すときの唯一興味深い部分は、拡張メソッドへの2番目の引数としてデリゲートを介してkeyプロパティを見つける方法を指示する必要があることです。

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department model)
{
  db.ApplyDetachedPropertyChanges(model, x => x.Id);
  db.SaveChanges();
}

そして拡張方法:

public static class EfExtensions
{
  public static void ApplyDetachedPropertyChanges<T>(this ObjectContext db, T entity, Func<T, int> getIdDelegate)
  where T : EntityObject
  {
    var entitySetName = db.DefaultContainerName + "." + entity.GetType().Name;
    var id = getIdDelegate(entity);
    var entityKey = new EntityKey(entitySetName, "Id", id);

    db.Attach(new Department {Id = id, EntityKey = entityKey});
    db.AcceptAllChanges();

    db.ApplyPropertyChanges(entitySetName, entity);
  }
}

拡張メソッドはAcceptAllChangesを呼び出しているので、一度に複数のエンティティで更新を行っている場合はこれを呼び出すことに注意する必要があります - 注意しないと更新を「失う」可能性があります。そのため、このアプローチは単純な更新シナリオに非常に適しています。たとえば、多数のMVCアクションメソッド:)



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ