2009-04-29 64 views
3

改變實體我有以下情形:中的EntityFramework

  1. 實體從數據庫加載。
  2. 其中之一是在用戶可以編輯該實體的屬性的窗體(WPF UserControl)中呈現給用戶。
  3. 用戶可以決定將更改應用於實體或取消編輯。

我該如何使用EntityFramework實現這樣的事情?

我的問題是,當我直接將UI綁定到實體的屬性時,每個更改都會立即應用於實體。我想延遲到用戶按下OK的時刻,並且實體已成功驗證

我想過在分離的實體經過驗證後,加載實體NoTracking並調用ApplyPropertyChanges,但我並不完全確定這樣做的正確方法。 MSDN中EntityFramework的文檔非常稀少。

我可以想到的另一種方法是RefreshStoreWins的實體,但我不喜歡重置Cancel上的更改,而不是在Ok上應用更改。

有沒有人有一個很好的教程或樣本?

回答

3

一種選擇是你說的做一個沒有跟蹤的查詢。

ctx.Customers.MergeOption = MergeOption.NoTracking; 
var customer = ctx.Customers.First(c => c.ID == 232); 

然後客戶可以修改'customer'在內存要求,並沒有在上下文中實際發生的情況。

現在,當你想真正讓你可以做到這一點的變化:

// get the value from the database 
var original = ctx.Customers.First(c => c.ID == customer.ID); 
// copy values from the changed entity onto the original. 
ctx.ApplyPropertyChanges(customer); . 
ctx.SaveChanges(); 

現在,如果你是使用查詢無論是性能或併發的原因不舒服,你可以添加一個新的擴展方法AttachAsModified(.. )到ObjectContext。

,看起來是這樣的:

public static void AttachAsModified<T>(
    this ObjectContext ctx, 
    string entitySet, 
    T entity) 
{ 
    ctx.AttachTo(entitySet, entity); 

    ObjectStateEntry entry = 
      ctx.ObjectStateManager.GetObjectStateEntry(entity); 

    // get all the property names 
    var propertyNames = 
      from s in entry.CurrentValues.DataRecordInfo.FieldMetadata 
      select s.FieldType.Name; 

    // mark every property as modified  
    foreach(var propertyName in propertyNames) 
    { 
     entry.SetModifiedProperty(propertyName); 
    } 
} 

現在你可以這樣寫代碼:

ctx.Customers.MergeOption = MergeOption.NoTracking; 
var customer = ctx.Customers.First(); 
// make changes to the customer in the form 
ctx.AttachAsModified("Customers", customer); 
ctx.SaveChanges(); 

現在你有沒有併發或extranous查詢。

現在唯一的問題是處理FK屬性。你或許應該看看我的祕訣指數爲幫助在這裏:http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx

希望這有助於

亞歷

+0

我目前正在與ApplyPropertyChanges方式實現,但附加一個修改實體看起來也很有趣。 Thx爲輸入! – 2009-05-07 00:12:52

1

這樣做的正常方法是綁定到實現IEditableObject的東西。如果和如何符合實體框架,我不確定。

1

我也建議IEditableObject,另外還有IDataErrorInfo。我基本上有一個實體的視圖模型,它將實體作爲構造函數參數(基本上是一個包裝對象)。

在BeginEdit中,我將實體屬性複製到我的viewmodel,所以如果我做CancelEdit,數據只在ViewModel中更改,原始實體沒有改變。在EndEdit中,我只是再次將ViewModel屬性應用於實體,或者僅當驗證成功時才應用。

驗證我使用IDataErrorInfo的方法。我只是實現IDataErrorInfo.Error,以便它通過IDataErrorInfo [string columnName]檢查每個屬性名稱並連接最終的錯誤消息。如果它是空的,一切都好。 (不知道是否錯誤是用這種方式,但我這樣做)

如果我有其他實體附加到我的原始實體,如Customer.Orders,我創建它們作爲嵌套的ViewModels在原始實體的ViewModel 。原來的ViewModel在它自己的那些方法的實現中調用它的子模型的Begin,Cancel,EndEdit/Error方法。

這是一個更多的工作,但我認爲這是值得的,因爲在BeginEdit和EndEdit之間,你可以肯定沒有任何變化沒有你的注意。並且啓用INotifyPropertyChanged屬性的代碼片段也有很多幫助。