我有以下场景:
- 实体从数据库加载。
- 其中一个以表单(WPF 用户控件)的形式呈现给用户,用户可以在其中编辑该实体的属性。
- 用户可以决定将更改应用于实体或取消编辑。
我如何使用 EntityFramework 实现类似的东西?
我的问题是,当我将 UI 直接绑定(bind)到实体的属性时,每个更改都会立即应用到实体。我想将其延迟到用户按下 OK 并且实体被验证成功的那一刻。
我考虑过使用 NoTracking
加载实体并在验证分离的实体后调用 ApplyPropertyChanges
,但我不完全确定正确的方法. MSDN 上的 EntityFramework 文档非常稀少。
我能想到的另一种方法是使用 StoreWins
来Refresh
实体,但我不喜欢在 Cancel 时重置更改而不是在 Ok 时应用更改。
有人有好的教程或示例吗?
最佳答案
一个选项是您所说的执行无跟踪查询。
ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First(c => c.ID == 232);
然后客户可以根据需要在内存中修改'customer'
,上下文中实际上什么也没有发生。
现在,当您真正想要进行更改时,您可以这样做:
// get the value from the database
var original = ctx.Customers.First(c => c.ID == customer.ID);
// copy values from the changed entity onto the original.
ctx.ApplyPropertyChanges(customer); .
ctx.SaveChanges();
现在,如果您出于性能或并发原因对查询感到不舒服,您可以向 ObjectContext 添加一个新的扩展方法 AttachAsModified(...)。
看起来像这样:
public static void AttachAsModified<T>(
this ObjectContext ctx,
string entitySet,
T entity)
{
ctx.AttachTo(entitySet, entity);
ObjectStateEntry entry =
ctx.ObjectStateManager.GetObjectStateEntry(entity);
// get all the property names
var propertyNames =
from s in entry.CurrentValues.DataRecordInfo.FieldMetadata
select s.FieldType.Name;
// mark every property as modified
foreach(var propertyName in propertyNames)
{
entry.SetModifiedProperty(propertyName);
}
}
现在你可以这样写代码了:
ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First();
// make changes to the customer in the form
ctx.AttachAsModified("Customers", customer);
ctx.SaveChanges();
现在您没有并发或外部查询。
现在唯一的问题是处理 FK 属性。您可能应该在此处查看我的提示索引以获取帮助:http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx
希望对你有帮助
亚历克斯
关于c# - 更改 EntityFramework 中的实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/803022/