2011-08-31 41 views
1

與正常情況不同,我擁有實際可行的代碼,但我想知道它是否是唯一的(或最佳方法)。EntityFramework:使用獨立實體更新單個字段

基本的想法是我有一個現有的應用程序,手工製作的數據層被移植到實體框架。作爲最小化代碼更改的折衷方案,我正在使用現有的方法,這些方法往往採取更分離的方法。例如,我有很多事情是這樣的:

UpdateNote(int noteId, string note) 

我似乎有一個不需要這種類型的更新工作的方法再取出:

var context = new MyEntities(); 
context.Configuration.ValidateOnSaveEnabled = false; 
var note = new Model.Note{ Id = noteId, Note = ""}; 
context.Notes.Attach(note); 
note.Note = "Some Note"; 
context.SaveChanges(); 

這是一個有點醜陋的(儘管簡明扼要),所以我想知道是否有更好的方法來使用EF?這種方法的任何缺點,除了失去內置的驗證?

這是一種將在我的應用程序中使用的模式。

+0

我有一個更好的擴展方法,我會在一點點。它是一種從網上抓取的AttachAsModified I變體,在這些情況下效果很好,無需知道道具名稱。 –

+0

回來看看這個 - 你將失去你的DataAnnotations驗證(如果這就是你的意思),但是如果你已經定義了任何(例如在代碼中使用IsRequired()方法),你仍然會保留你的實體框架驗證 –

回答

3

以下DbContext的擴展方法是避免初始化您的實體,其中某些值與您想要更改的值不同。

public static class EFExtensions 
{ 
    public static void MarkAsModified(this DbContext context, object entity, 
     params string[] properties) 
    { 
     foreach (var property in properties) 
      context.Entry(entity).Property(property).IsModified = true; 
    } 
} 

然後,您可以使用這種方式:

var context = new MyEntities(); 
context.Configuration.ValidateOnSaveEnabled = false; 

var note = new Model.Note { Id = noteId }; // only key properties required to set 

note.Note = "Some Note"; 
note.SomeOtherProperty = 1234; 
note.AndAnotherProperty = "XYZ"; 

context.Notes.Attach(note); 
context.MarkAsModified(note, "Note", "SomeOtherProperty" , "AndAnotherProperty"); 

context.SaveChanges(); 

注:這僅適用於標量的屬性,而不是導航屬性的作品。

除了驗證,我可以想象這種方法對於正確的併發檢查是有問題的。

編輯

根據下面併發@Adam Tuliper的評論很可能不是一個問題,因爲當實體手動附加到上下文(不包括從數據庫讀取它)併發檢查被跳過,標記爲修改爲向數據庫發送UPDATE命令。它只是覆蓋數據庫中的最新版本。感謝Adam指出了這一點!

+0

看看你在說什麼,初始化,我不喜歡它使用字符串文字的屬性名稱。但是,併發檢查會有什麼問題? –

+0

@cadmium:我實際上不確定它是否有問題。但我的理解是,EF中的樂觀併發檢查依賴於存儲在數據庫中的併發令牌(這是實體的某些屬性)。當您保存實體(UPDATE語句)時,將對象中的併發標記與數據庫中的值進行比較。如果它們不同,你會得到一個樂觀的併發異常,並需要決定做什麼。如果你不知道最新的併發令牌(當你沒有從數據庫中讀取並且只是附加一個新的實例到上下文時就是這種情況)(...繼續...) – Slauma

+0

(。 ..continued ...)你的令牌在實體和數據庫中總是不同的,所以你總會得到一個併發衝突。這只是假設性的,我並不知道如何進行併發檢查的細節。順便說一句:我不喜歡我的回答了:屬性名稱的字符串=重構不好。可以引入一個屬性名稱提取器來再次強烈地鍵入。但所有這些反思...不好。也許你的手寫方式更好,至少更快。 – Slauma

2

如果我們現在要保存它,請參閱下面的代碼,用於輕鬆地將斷開的對象附加到圖形上。


public static class EntityFrameworkExtensions 
{ 
    /// <summary> 
    /// This class allows you to attach an entity. 
    /// For instance, a controller method Edit(Customer customer) 
    /// using ctx.AttachAsModified(customer); 
    /// ctx.SaveChanges(); 
    /// allows you to easily reattach this item for udpating. 
    /// Credit goes to: http://geekswithblogs.net/michelotti/archive/2009/11/27/attaching-modified-entities-in-ef-4.aspx 
    /// </summary> 
    public static void AttachAsModified<T>(this ObjectSet<T> objectSet, T entity) where T : class 
    { 
     objectSet.Attach(entity); 
     objectSet.Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified); 
    } 

    /// <summary> 
    /// This marks an item for deletion, but does not currently mark child objects (relationships). 
    /// For those cases you must query the object, include the relationships, and then delete. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="objectSet"></param> 
    /// <param name="entity"></param> 
    public static void AttachAsDeleted<T>(this ObjectSet<T> objectSet, T entity) where T : class 
    { 
     objectSet.Attach(entity); 
     objectSet.Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Deleted); 
    } 

    public static void AttachAllAsModified<T>(this ObjectSet<T> objectSet, IEnumerable<T> entities) where T : class 
    { 
     foreach (var item in entities) 
     { 
      objectSet.Attach(item); 
      objectSet.Context.ObjectStateManager.ChangeObjectState(item, EntityState.Modified); 
     } 
    } 
} 
+0

是的,這很容易實現,但它也很昂貴,因爲通過將實體狀態設置爲Modified,EF將向所有*標量屬性發送完整的更新命令,無論它們是否真正更改。這是一種「蠻力」更新。 – Slauma

+0

是的,但不幸的是,在大多數情況下,我們不知道網絡上發生了什麼變化。我們從一個頁面轉到一些不連通的項目。 MVC的情況更是如此,您的模型作爲不連通的項目傳入。然後您需要將其發送到數據庫或加載對象,然後將該模型與該對象合併。在這種情況下,您不僅可以保存所有財產,還必須滿負荷運轉。如果您使用AttachAsModified,則可以先不加載加載。除非你的數據頁面接近8k的限制(或者使用varchar(max)項目或更大的數據頁面,否則我不確定這個性能是否會成爲問題 –

+0

我同意如果你不知道改變了什麼,它是一種工作方式。但是我可能是錯的 – Slauma

相關問題