125 votes

Annuler les modifications apportées aux entités du cadre des entités

Il s'agit peut-être d'une question triviale, mais.. : Étant donné que le cadre des entités ADO.NET suit automatiquement les modifications (dans les entités générées) et conserve donc les valeurs d'origine, comment puis-je annuler les modifications apportées aux objets de l'entité ?

J'ai un formulaire qui permet à l'utilisateur de modifier un ensemble d'entités "Client" dans une vue en grille.

Maintenant j'ai deux boutons "Accepter" et "Revenir en arrière" : si "Accepter" est cliqué, j'appelle Context.SaveChanges() et les objets modifiés sont réécrits dans la base de données. Si l'on clique sur "Revenir en arrière", j'aimerais que tous les objets retrouvent leurs valeurs de propriété d'origine. Quel serait le code pour cela ?

Gracias

169voto

T.Rahgooy Points 358

Interroger le ChangeTracker de DbContext pour les éléments sales. Définissez l'état des éléments supprimés comme inchangé et celui des éléments ajoutés comme détaché. Pour les éléments modifiés, utilisez les valeurs originales et définissez les valeurs actuelles de l'entrée. Enfin, définissez l'état de l'entrée modifiée sur inchangé :

public void RollBack()
{
    var context = DataContextFactory.GetDataContext();
    var changedEntries = context.ChangeTracker.Entries()
        .Where(x => x.State != EntityState.Unchanged).ToList();

    foreach (var entry in changedEntries)
    {
        switch(entry.State)
        {
            case EntityState.Modified:
                entry.CurrentValues.SetValues(entry.OriginalValues);
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Deleted:
                entry.State = EntityState.Unchanged;
                break;
        }
    }
 }

3 votes

Merci - cela m'a vraiment aidé !

5 votes

Vous devriez probablement définir les valeurs d'origine des entrées supprimées également. Il est possible que vous ayez d'abord modifié un élément et que vous l'ayez ensuite supprimé.

28 votes

Réglage de State a EntityState.Unchanged remplacera toutes les valeurs avec Original Values de sorte qu'il n'est pas nécessaire d'appeler SetValues méthode.

72voto

Ladislav Mrnka Points 218632

Il n'y a pas d'opération de rétablissement ou d'annulation des modifications dans EF. Chaque entité a ObjectStateEntry sur ObjectStateManager . L'entrée de l'état contient les valeurs originales et actuelles. Vous pouvez donc utiliser les valeurs originales pour écraser les valeurs actuelles mais vous devez le faire manuellement pour chaque entité. Les modifications apportées aux propriétés de navigation et aux relations ne seront pas prises en compte.

La façon la plus courante de "revenir sur les changements" est de disposer du contexte et de recharger les entités. Si vous voulez éviter le rechargement, vous devez créer des clones d'entités et modifier ces clones dans le nouveau contexte de l'objet. Si l'utilisateur annule les changements, vous aurez toujours les entités originales.

4 votes

@LadislavMrnka Bien sûr. Context.Refresh() est un contre-exemple à votre affirmation selon laquelle il n'y a pas d'opération de retour en arrière ? En utilisant Refresh() semble une meilleure approche (c'est-à-dire plus facile à cibler sur des entités spécifiques) que de disposer du contexte et de perdre toutes les modifications suivies.

15 votes

@robjb : Non. Refresh est capable de rafraîchir seulement une entité unique ou une collection d'entités que vous définissez manuellement mais la fonctionnalité de rafraîchissement n'affecte que les propriétés simples (pas les relations). Elle ne résout pas non plus le problème des entités ajoutées ou supprimées.

34voto

Lu55 Points 2339
dbContext.Entry(entity).Reload();

Conformément à MSDN :

Recharge l'entité à partir de la base de données en écrasant toutes les valeurs des propriétés avec les valeurs de la base de données. L'entité sera dans l'état Unchanged après l'appel de cette méthode.

Notez que le retour en arrière par la requête à la base de données a quelques inconvénients :

  • le trafic du réseau
  • Surcharge de la base de données
  • l'augmentation du temps de réponse des applications

17voto

Matyas Points 121

Cela a marché pour moi :

dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);

item est l'entité client à rétablir.

13voto

Guish Points 879

Un moyen facile sans suivre les changements. Cela devrait être plus rapide que de regarder chaque entité.

public void Rollback()
{
    dataContext.Dispose();
    dataContext= new MyEntities(yourConnection);
}

0 votes

Le temps de création d'un seul objet entité... qui est de quelques ms (50 ms). Boucler dans la collection peut être plus rapide ou plus long en fonction de sa taille. En termes de performance, O(1) est rarement un problème comparé à O(n). Notation du grand O

0 votes

Ne pas vous suivre - performance d'élimination et de recréation de la connexion. Je l'ai testé sur un projet existant et il s'est terminé un peu plus rapidement que ci-dessus. Rollback ce qui en fait un bien meilleur choix si l'on veut rétablir l'état entier de la base de données. Le retour à l'état initial pourrait faire un choix sélectif.

0 votes

N" signifie le nombre d'objets. Recréer une connexion prend environ 50 ms... O(1) signifie que c'est toujours le même temps. 50ms+0*n= 50ms . O(n) signifie que la performance est influencée par le nombre d'objets... la performance est peut-être 2ms+0.5ms*n ... donc en dessous de 96 objets, ce serait plus rapide mais le temps augmenterait linéairement avec la quantité de données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X