如何将部分更新操作从 ObjectContext 转换为 DbContext

Posted

技术标签:

【中文标题】如何将部分更新操作从 ObjectContext 转换为 DbContext【英文标题】:How to transition partial update operation from ObjectContext to DbContext 【发布时间】:2017-10-05 10:21:06 【问题描述】:

我正在使用实体框架 5.0。我正在将我的应用程序从 ObjectContext 更改为 DbContext 模型。 DbContext 应该是按照microsoft 推荐的方法。我使用数据库 forst 方法,并生成了模型表单数据库。 但是,在第一个简单的任务中就有一个问题。即记录的简单更新被破坏。

让我们有一个简单的表项,仅供说明:

Item
(
    ItemId int NOT NULL,    -- Primary key
    Name nvarchar(50) NOT NULL,
    Description NVARCHAR(50) 
)

我注意到使用 DbContext 不像 ObjectContext 那样支持更新记录。 在我的应用程序中,我有一个简单的更新方法。

public void UpdateItem()

      MyContext context = new MyContext();
      Item item = new Item();
      item.ItemId = 666;
      context.Items.Attach(item); 
      // From this point onward EF tracks the changes I make to Item
      Item.Description = "Some description";
      context.SaveChanges();

使用 ObjectContext 此方法正确更新记录。使用 SQL 探查器,我可以看到它生成了类似这样的内容(非常简单!!!)

 UPDATE Item
 SET Description = 'Some description'
 WHERE ItemId = 666

但是,如果我尝试在 DbContext 中执行相同的操作,则会出现异常:

System.Exception: Items.aspx.cs - logged from CustomError() ---> System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
   at System.Data.Entity.Internal.InternalContext.SaveChanges()
   at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
   at System.Data.Entity.DbContext.SaveChanges()

并且没有向 Sql server 发出数据库 UPDATE。 我猜 DbContext 验证了所有属性并且属性 Name 为空。这是设计使然。我不打算修改它,我什至不知道它是什么,我不需要知道它是什么。 只有属性描述被更改。显然 ObjectContext 没有正确跟踪更改。 如何解决这个问题?

我已经研究了这个问题,并发现了有关更新记录的内容。 例如这个链接:https://***.com/a/15339512/4601078

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

但这是可怕的代码。对于每个属性都应该添加一行:

entry.Property(e => e.Email).IsModified = true;

这会产生难看的不可读代码,我怀疑 lamda 表达式的性能并不出色。

更糟糕的是那些建议往返数据库以获取填充了所有属性的现有记录、更新它并保存更改的人。就性能而言,这是不行的。

那么,如何处理简单的实体更新,或者这个 DbContext 只是微软死胡同集合中的另一个项目,没有真正的用途?

【问题讨论】:

【参考方案1】:

如果您确定您应用的更改是有效的,或者您有自定义代码来验证它们,则可以完全关闭 EF 验证:

db.Configuration.ValidateOnSaveEnabled = false;

只要您按照自己的方式进行操作就可以了:附加一个具有已知 ID 的新实体(又名 存根实体),然后修改其属性。 EF 只会更新它检测到已被修改的属性(实际上是通过比较原始值和当前值,而不是像 ObjectContext 那样通过更改通知)。您不应将实体本身标记为已修改。

如果您不想关闭 EF 的验证,但又不想将单个属性标记为已修改,我认为 this 可能是一个有用的替代方案(Alex 的回答引起了我的注意)。

【讨论】:

【参考方案2】:

DbContext 并不真正通过观察属性来跟踪更改,它会将值与先前已知的值进行比较。并且验证始终适用于整个实体,因此如果您想以这种方式做事,唯一真正的选择是在此操作期间禁用验证。见Entity Framework validation with partial updates

【讨论】:

我知道这是一个验证异常。只是验证本身(或跟踪)是错误的。 对,对不起,更新答案。 嗯。您提供的链接可能与建议使用 dbContext.Configuration.ValidateOnSaveEnabled = false 的答案有关。虽然不是解决方案,但至少是一种解决方法。我相信修改后的属性仍应得到验证。但这是一种解决方法,我在更新之前在代码中进行了验证。因提供一半有用的链接和搜索短语“部分更新”而受到支持。 一半有用吗?这些都是相当高的标准。但是您可能想阅读该问题的所有答案,还可以选择在事后删除未更改属性的验证错误(仍然不理想,但很好)。

以上是关于如何将部分更新操作从 ObjectContext 转换为 DbContext的主要内容,如果未能解决你的问题,请参考以下文章

ObjectContext.Refresh()?

每组操作的可重用 ObjectContext 还是新的 ObjectContext?

使用 ObjectContext 获取关系记录的主键

我应该如何监听从 ObjectContext 添加/删除的实体?

解决“ObjectContext 实例已被释放,不能再用于需要连接的操作”InvalidOperationException

此 ObjectContext 实例已释放,不可再用于需要连接的操作。