我正在使用自定义方法来跟踪 n 层断开连接的实体类的各个修改属性。我从
实体框架编程:Julia Lerman 和 Rowan Miller (O'Reilly) 的 DbContext。版权所有 2012 Julia Lerman 和 Rowan Miller,978-1-449-31296-1。
代码是:
public void ApplyChanges<TEntity>(TEntity root) where TEntity : class, IObjectWithState {
// bind the entity back into the context
dbContext.Set<TEntity>().Add(root);
// throw exception if entity does not implement IObjectWithState
CheckForEntitiesWithoutStateInterface(dbContext);
foreach (var entry in dbContext.ChangeTracker.Entries<IObjectWithState>()) {
IObjectWithState stateInfo = entry.Entity;
if (stateInfo.State == RecordState.Modified) {
// revert the Modified state of the entity
entry.State = EntityState.Unchanged;
foreach (var property in stateInfo.ModifiedProperties) {
// mark only the desired fields as modified
entry.Property(property).IsModified = true;
}
} else {
entry.State = ConvertState(stateInfo.State);
}
}
dbContext.SaveChanges();
}
此方法的目的是让 EF 知道只有一组预定义的实体字段已准备好在下次调用 SaveChanges() 时进行更新。这是为了解决实体在 ASP.NET MVC 3 中工作的问题,如下所示:
在初始页面加载时:控制器的 Get 操作正在加载实体对象并将其作为参数传递给视图。
视图生成用于编辑实体的 2 个字段的控件,并将记录的 ID 保存在隐藏字段中。
当点击 [save] 并将实体发布回控制器时,除了视图中保留的 3 个字段之外,所有字段都带有一个空值。这是 MVC 绑定管理器的默认行为。
如果我将更改保存回数据库,更新查询当然会用如下语句覆盖非映射字段:
UPDATE non_mapped_field_1 = NULL, ..., mapped_field_1 = 'mapped_value_1', mapped_field_2 = 'mapped_value_2', ... non_mapped_field_n = NULL WHERE ID = mapped_field_3
这就是我尝试单独跟踪字段并仅更新我感兴趣的那些字段的原因。在使用 ApplyChanges() 调用自定义方法之前,我正在添加要包含在更新中的字段列表IObjectWithState.ModifiedProperties 列表,以获取 SQL 语句如下:
UPDATE mapped_field_1 = 'mapped_value_1', mapped_field_2 = 'mapped_value_2' WHERE id = mapped_value_3
问题是,在 ApplyChanges 中将其中一个字段标记为已修改时,即:
entry.Property(property).IsModified = true;
系统抛出以下异常:
{System.InvalidOperationException: Member 'IsModified' cannot be called for property 'NotifyCEDeadline' on entity of type 'User' because the property is not part of the Entity Data Model.
at System.Data.Entity.Internal.InternalPropertyEntry.ValidateNotDetachedAndInModel(String method)
at System.Data.Entity.Internal.InternalPropertyEntry.set_IsModified(Boolean value)
at System.Data.Entity.Infrastructure.DbPropertyEntry.set_IsModified(Boolean value)
...
所以问题是。有一种方法可以绕过这个 EF 验证,或者让上下文知道我正在尝试更改的这个系统属性 (IsModified) 的存在吗?
架构总结:
- EF 代码优先(注解 + Fluent API)
- Oracle .NET EF 数据提供程序 (ODAC)
使用 nInject.MVC 将上下文注入到自定义业务上下文 => 这就是我自定义 ApplyChanges() 方法的原因
使用 (var context = new BreakAwayContext()){ context.Set().Add(root);
对已经初始化的 dbcontext 的简单调用
dbContext.Set().Add(root);
Oracle 数据库是手动创建的,即没有 EF 的帮助,因此不使用 EF 元数据表。
谢谢,伊万。