2011-04-06 49 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

相关问题