我有以下情况:
我如何使用EntityFramework实现类似的功能?
我的问题是,当我将UI直接绑定到实体的属性时,每个更改都会立即应用于实体。我想将此延迟到用户按下OK并且已成功验证的那一刻。
我考虑过使用NoTracking
加载实体并在验证分离的实体后调用ApplyPropertyChanges
,但我不完全确定正确的方法。 MSDN上的EntityFramework的文档非常稀疏。
我能想到的另一种方法是使用Refresh
来StoreWins
实体,但我不喜欢在取消时重置更改,而不是在Ok时应用更改。
有没有人有一个好的教程或样本?
答案 0 :(得分:3)
您所说的一个选项是执行无跟踪查询。
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
希望这有帮助
亚历
答案 1 :(得分:1)
执行此操作的常规方法是绑定到实现IEditableObject
的内容。如果和如何适应实体框架,我不确定。
答案 2 :(得分:1)
我也建议IEditableObject,另外还有IDataErrorInfo。
我这样做的方式是,我基本上有一个实体的视图模型,它将实体作为构造函数参数(基本上是一个包装器对象)。
在BeginEdit中,我将实体属性复制到我的viewmodel,因此,如果我执行CancelEdit,则仅在ViewModel中更改数据,并且原始实体未更改。在EndEdit中,我只是再次将ViewModel属性应用于实体,或者仅在验证成功时才应用。
对于验证,我使用IDataErrorInfo的方法。我只是实现IDataErrorInfo.Error,以便它通过IDataErrorInfo [string columnName]检查每个属性名称并连接最终的错误消息。如果它是空的,一切都很好。 (不确定错误是否意味着以这种方式使用,但我这样做)
如果我有其他实体附加到我的原始实体,例如Customer.Orders,我将它们创建为原始实体的ViewModel中的嵌套ViewModel。原始的ViewModel在它自己的那些方法的实现中调用它的subModels的Begin-,Cancel-,EndEdit / Error方法。
这是一个更多的工作,但我认为这是值得的,因为在BeginEdit和EndEdit之间,你可以非常肯定没有你注意到它没有任何改变。拥有支持INotifyPropertyChanged的属性的代码片段也有很大帮助。