Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF4 Context.ApplyCurrentValues does not update current values

I have a entity that I retrieve as follows and is detached from the context:

ctx.Reviews.MergeOption = MergeOption.NoTracking;

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

I then make changes to an object in the relationship:

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

I then attach the Object and loop the children and change it's entity state if needed. When save changes is done nothing is updated.:

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();
like image 296
Big Joe Avatar asked Feb 26 '23 23:02

Big Joe


1 Answers

Because you start with MergeOption.NoTracking your entities are Detached. Then you modify and attached them. You should be aware that Attach results in an Unchanged EntityState — that is, it has not changed since it was attached to the context. So that both the original and current values have the same set of values: the modified ones. That's why it does not get updated once you call SaveChanges method.

I think you also misunderstood the purpose of ApplyCurrentValues method:
It will take the values of the provided detached entity and use its EntityKey to locate the same entity in the context. Then it will replace the attached entity’s current scalar values with the property values from the detached entity.
In your case where you already attached the detached entity, you don't really need to call it, instead you need to Change the state of your ReviewNote entity to Modified so that EF will execute appropiate update methods against your data store:

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


EDIT: Another approach would be to run the same query and get the ReviewNote objects into the memory and then call ApplyCurrentValues on each of them so that only the ones that has a changed property would go into Modified state:

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

Also note that ApplyCurrentValues does only work with the scalar properties on a single entity and would not take navigation properties into account, otherwise we would just call it one time on Review object without having to go into a loop to apply it on each and every ReviewNote.

like image 110
Morteza Manavi Avatar answered Apr 27 '23 01:04

Morteza Manavi