2009-04-29 57 views
3

改变实体我有以下情形:中的EntityFramework

  1. 实体从数据库加载。
  2. 其中之一是在用户可以编辑该实体的属性的窗体(WPF UserControl)中呈现给用户。
  3. 用户可以决定将更改应用于实体或取消编辑。

我该如何使用EntityFramework实现这样的事情?

我的问题是,当我直接将UI绑定到实体的属性时,每个更改都会立即应用于实体。我想延迟到用户按下OK的时刻,并且实体已成功验证

我想过在分离的实体经过验证后,加载实体NoTracking并调用ApplyPropertyChanges,但我并不完全确定这样做的正确方法。 MSDN中EntityFramework的文档非常稀少。

我可以想到的另一种方法是RefreshStoreWins的实体,但我不喜欢重置Cancel上的更改,而不是在Ok上应用更改。

有没有人有一个很好的教程或样本?

回答

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(); 

现在,如果你是使用查询无论是性能或并发的原因不舒服,你可以添加一个新的扩展方法AttachAsModified(.. )到ObjectContext。

,看起来是这样的:

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(); 

现在你有没有并发或extranous查询。

现在唯一的问题是处理FK属性。你或许应该看看我的秘诀指数为帮助在这里:http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx

希望这有助于

亚历

+0

我目前正在与ApplyPropertyChanges方式实现,但附加一个修改实体看起来也很有趣。 Thx为输入! – 2009-05-07 00:12:52

1

这样做的正常方法是绑定到实现IEditableObject的东西。如果和如何符合实体框架,我不确定。

1

我也建议IEditableObject,另外还有IDataErrorInfo。我基本上有一个实体的视图模型,它将实体作为构造函数参数(基本上是一个包装对象)。

在BeginEdit中,我将实体属性复制到我的viewmodel,所以如果我做CancelEdit,数据只在ViewModel中更改,原始实体没有改变。在EndEdit中,我只是再次将ViewModel属性应用于实体,或者仅当验证成功时才应用。

验证我使用IDataErrorInfo的方法。我只是实现IDataErrorInfo.Error,以便它通过IDataErrorInfo [string columnName]检查每个属性名称并连接最终的错误消息。如果它是空的,一切都好。 (不知道是否错误是用这种方式,但我这样做)

如果我有其他实体附加到我的原始实体,如Customer.Orders,我创建它们作为嵌套的ViewModels在原始实体的ViewModel 。原来的ViewModel在它自己的那些方法的实现中调用它的子模型的Begin,Cancel,EndEdit/Error方法。

这是一个更多的工作,但我认为这是值得的,因为在BeginEdit和EndEdit之间,你可以肯定没有任何变化没有你的注意。并且启用INotifyPropertyChanged属性的代码片段也有很多帮助。