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不包含ObjectStateEntry,其中引用了“Sample.Models.Department”類型的對象。

兩個EntityKeys是平等的。為什麼第二塊代碼失敗?我該如何解決?

熱門答案

你的第二個代碼塊失敗的原因是因為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列的任何內容。調用該方法唯一有趣的部分是你需要告訴它如何通過委託找到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動作方法:)



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因