如何将部分更新操作从 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 还是新的 ObjectContext?
我应该如何监听从 ObjectContext 添加/删除的实体?
解决“ObjectContext 实例已被释放,不能再用于需要连接的操作”InvalidOperationException