EF4 Context.ApplyCurrentValues不更新当前值

时间:2010-10-28 00:05:42

标签: entity-framework c#-4.0

我有一个实体,我按如下方式检索并与上下文分离:

ctx.Reviews.MergeOption = MergeOption.NoTracking;

Review review = (from r in ctx.Reviews.Include("ReviewNotes")
                 where r.ReviewID == reviewID
                 select r).First();

然后我对关系中的对象进行了更改:

if (review.ReviewNotes.Count > 0)
{
  ReviewNote r = review.ReviewNotes.ElementAt(0);
  r.Note = "Ugg " + DateTimeOffset.Now.ToString();
  r.CreatedDate = DateTimeOffset.Now;
}

然后我附加了Object并循环子节点并在需要时更改它的实体状态。保存更改完成后,不会更新任何内容。

ctx.Reviews.Attach(review);
foreach (ReviewNote item in review.ReviewNotes)
{
   if (item.ReviewNoteID == 0)
   {
       ctx.ObjectStateManager.ChangeObjectState(item, EntityState.Added);
   }
   else
   {
       key = ctx.CreateEntityKey("ReviewNotes", item);
       if (ctx.TryGetObjectByKey(key, out original))
       {
           ctx.ApplyCurrentValues<ReviewNote>(key.EntitySetName, item);
       }

   }
 }

ctx.ObjectStateManager.ChangeObjectState(review, EntityState.Modified);
ctx.SaveChanges();

1 个答案:

答案 0 :(得分:8)

因为您从MergeOption.NoTracking开始,所以您的实体为Detached。然后你修改并附加它们。您应该知道 附加 会导致 未更改 EntityState - 也就是说,它没有更改,因为它是附在上下文中。这样原始值和当前值都具有相同的值集:修改后的值。 这就是为什么一旦你调用SaveChanges方法它就不会更新。

我想你也误解了ApplyCurrentValues方法的目的:
它将获取所提供的分离实体的值,并使用其EntityKey在上下文中定位同一实体。然后,它将使用分离实体的属性值替换附加实体的当前标量值。
在您已经附加分离实体的情况下,您实际上不需要调用它,而是需要将ReviewNote实体的状态更改为已修改,以便EF执行适用于您的数据存储的更新方法:

ctx.Reviews.Attach(review);
foreach (ReviewNote item in review.ReviewNotes) {
   if (item.ReviewNoteID == 0) {
       ctx.ObjectStateManager.ChangeObjectState(item, EntityState.Added);
   }
   else {
       key = ctx.CreateEntityKey("ReviewNotes", item);
       if (ctx.TryGetObjectByKey(key, out original)) {
           // ctx.ApplyCurrentValues(key.EntitySetName, item);
           ctx.ObjectStateManager.ChangeObjectState(item, EntityState.Modified);
       }
   }
 }
ctx.ObjectStateManager.ChangeObjectState(review, EntityState.Modified);
ctx.SaveChanges();


修改 另一种方法是运行相同的查询并将ReviewNote对象放入内存中,然后在每个对象上调用ApplyCurrentValues,以便只有具有已更改属性的对象才会进入 Modified 状态:

// This time you don't need to attach:
//ctx.Reviews.Attach(review);
// Make sure you have them in the memory:
Review review2 = (from r in ctx.Reviews.Include("ReviewNotes")
                 where r.ReviewID == reviewID
                 select r).First();
foreach (ReviewNote item in review.ReviewNotes) {
   if (item.ReviewNoteID == 0) {
       ctx.ReviewNotes.AddObject(item);
   }
   else {
       key = ctx.CreateEntityKey("ReviewNotes", item);
       if (ctx.TryGetObjectByKey(key, out original)) {
           // Note that the item is a detached object now: 
           ctx.ApplyCurrentValues(key.EntitySetName, item);
       }
   }
 }
ctx.ObjectStateManager.ChangeObjectState(review, EntityState.Modified);
ctx.SaveChanges();

另请注意, ApplyCurrentValues 仅适用于单个实体上的标量属性,并且不会考虑导航属性,否则我们只会调用它一次查看对象而无需进入循环以将其应用于每个ReviewNote。