2011-04-06 35 views
17

如何更新記錄的單個屬性而不先檢索它? 我問在EF代碼第一次4.1在實體框架中更新記錄的單個屬性代碼優先

的情況下說我有一類用戶,映射到表中的用戶數據庫:

class User 
{ 
    public int Id {get;set;} 
    [Required] 
    public string Name {get;set;} 
    public DateTime LastActivity {get;set;} 
    ... 
} 

現在我想更新用戶的LastActivity。我有用戶ID。我可以通過查詢用戶記錄,將新值設置爲LastActivity,然後調用SaveChanges()來輕鬆完成此操作。但是這會導致冗餘查詢。

我使用Attach方法解決問題。但是,因爲EF在Name上引發驗證異常(如果它爲null),我將Name設置爲隨機字符串(不會更新回DB)。但是,這似乎並沒有一個完美的解決方案:

using (var entities = new MyEntities()) 
{ 
    User u = new User {Id = id, Name="this wont be updated" }; 
    entities.Users.Attach(u); 
    u.LastActivity = DateTime.Now; 
    entities.SaveChanges(); 
} 

我將非常如果並欣賞有人可以給我提供一個更好的解決方案。並且原諒我的任何錯誤,因爲這是我第一次提出關於SO的問題。

回答

35

這是驗證實現的問題。驗證只能驗證整個實體。它不會按照預期驗證修改的屬性。正因爲如此的驗證應該在你想使用不完整的虛擬對象的場景被關閉:

using (var entities = new MyEntities()) 
{ 
    entities.Configuration.ValidateOnSaveEnabled = false; 

    User u = new User {Id = id, LastActivity = DateTime.Now }; 
    entities.Users.Attach(u); 
    entities.Entry(user).Property(u => u.LastActivity).IsModified = true; 
    entities.SaveChanges(); 
} 

這顯然是一個問題,如果你想使用相同的上下文爲虛擬對象的更新和全更新應該使用驗證的實體。驗證發生在SaveChanges,所以你不能說哪些對象應該被驗證,哪些不應該。

+0

我正在尋找一種方法來禁用驗證保存,但無法執行。感謝您的解決方案。 – 2011-04-07 04:07:40

+0

這個問題_seems_要在EF 5中修復。 – 2013-09-29 07:31:29

+0

我想指出的是,併發檢查可能會導致「0行更新」異常,因爲它將在where子句中添加一個檢查來匹配rowversion列。 (在我的情況下,它是空的,因爲它是一個存根) – Slight 2015-04-20 17:43:49

3

你可以嘗試一種黑客:
context.Database.ExecuteSqlCommand("update [dbo].[Users] set [LastActivity] = @p1 where [Id] = @p2",
new System.Data.SqlClient.SqlParameter("p1", DateTime.Now),
new System.Data.SqlClient.SqlParameter("p2", id));

+0

這不是黑客。但是,不幸的是,對於單個列的直接更新只能通過手中的整個實體以及像這樣的原始SQL字符串來完成。 – 2016-09-30 17:10:26

4

我實際上正在處理這個權利。我決定要在數據庫上下文中重寫ValidateEntity方法。

protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items) 
{ 
    var result = base.ValidateEntity(entityEntry, items); 

    var errors = new List<DbValidationError>(); 

    foreach (var error in result.ValidationErrors) 
    { 
     if (entityEntry.Property(error.PropertyName).IsModified) 
     { 
      errors.Add(error); 
     } 
    } 

    return new DbEntityValidationResult(entityEntry, errors); 
} 

我確定有一些洞可以戳穿它,但它似乎比替代品更好。

+1

這不是一個完整的代碼,但我喜歡這個想法。代碼的主要問題是你會陷入你試圖看到的屬性被修改而不是原始類型或複雜類型的情況下,因此會崩潰。您需要具有參考或收集的條件。 – 2015-09-13 18:52:09