EF4 Context.ApplyCurrentValues ne met pas à jour les valeurs actuelles

c#-4.0 entity-framework

Question

J'ai une entité que je récupère comme suit et qui est détachée du contexte:

ctx.Reviews.MergeOption = MergeOption.NoTracking;

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

J'apporte ensuite des modifications à un objet de la relation:

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

J'attache ensuite l'objet et boucle les enfants et change son état d'entité si nécessaire. Lorsque l'enregistrement des modifications est terminé, rien n'est mis à jour .:

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

Réponse acceptée

Parce que vous commencez avec MergeOption.NoTracking vos entités sont Detached . Ensuite, vous les modifiez et les attachez. Vous devez savoir que joindre les résultats dans un EntityState Inchangé â € » qui est, il n'a pas changé depuis qu'il a été attaché au contexte. De sorte que les valeurs d'origine et actuelle ont le même ensemble de valeurs: celles modifiées . C'est pourquoi il n'est pas mis à jour lorsque vous appelez la méthode SaveChanges.

Je pense que vous avez également mal compris l'objectif de la méthode ApplyCurrentValues :
Il utilisera les valeurs de l'entité détachée fournie et utilisera EntityKey pour localiser la même entité dans le contexte. Ensuite, il remplacera les valeurs scalaires actuelles de l'entité attachée par les valeurs de propriété de l'entité détachée.
Dans le cas où vous avez déjà attaché l'entité détachée, vous n'avez pas vraiment besoin de l'appeler, vous devez plutôt changer l'état de votre entité ReviewNote en Modifié afin que EF exécute les méthodes de mise à jour appropriées sur votre magasin de données:

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: Une autre approche serait d’exécuter la même requête et d’obtenir les objets ReviewNote dans la mémoire, puis d’appeler ApplyCurrentValues sur chacun d’eux afin que seuls ceux ayant une propriété modifiée passent à l’état 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();

Notez également que ApplyCurrentValues ne fonctionne qu'avec les propriétés scalaires d'une seule entité et ne prendrait pas en compte les propriétés de navigation. Sinon, nous l'appellerions une fois dans l'objet Review sans avoir à passer en boucle pour l'appliquer à chaque ReviewNote. .



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow