Annullare le modifiche nelle quadro di quadro quadro

questa potrebbe essere una domanda banale ma: Poiché il framework di quadro ADO.NET tiene automaticamente traccia delle modifiche (nelle quadro generate) e quindi mantiene i valori originali, come posso eseguire il rollback delle modifiche apportate agli oggetti quadro?

Ho una forma che consente all’utente di modificare un insieme di entity framework “Cliente” in una vista a griglia.

Ora ho due pulsanti “Accetta” e “Ripristina”: se si fa clic su “Accetta”, chiamo Context.SaveChanges() e gli oggetti modificati vengono riscritti nel database. Se si fa clic su “Ripristina”, vorrei che tutti gli oggetti ottenessero i loro valori di proprietà originali. Quale sarebbe il codice per questo?

Grazie

    Non è ansible annullare o annullare l’operazione di modifica in EF. Ogni quadro ha ObjectStateEntry in ObjectStateManager . La voce dello stato contiene valori originali e effettivi, quindi è ansible utilizzare i valori originali per sovrascrivere i valori correnti, ma è necessario farlo manualmente per ciascuna quadro. Non reverterà i cambiamenti nelle proprietà / relazioni di navigazione.

    Il modo comune per “annullare le modifiche” è disporre del contesto e ricaricare le quadro. Se vuoi evitare di ricaricare devi creare cloni di quadro e modificare quei cloni nel nuovo contesto di oggetti. Se l’utente annulla le modifiche, avrà comunque delle entity framework originali.

    Query ChangeTracker di DbContext per articoli sporchi. Imposta lo stato degli elementi eliminati su elementi non modificati e aggiunti a distaccati. Per gli articoli modificati, utilizzare i valori originali e impostare i valori correnti della voce. Infine imposta lo stato della voce modificata su invariato:

     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; } } } 
     dbContext.Entry(entity).Reload(); 

    Accroding a MSDN :

    Ricarica l’ quadro dal database sovrascrivendo eventuali valori di proprietà con valori dal database. L’ quadro sarà nello stato Invariato dopo aver chiamato questo metodo.

    Si noti che il ripristino della richiesta al database presenta alcuni svantaggi:

    • traffico di rete
    • Sovraccarico di DB
    • il maggiore tempo di risposta dell’applicazione

    Questo ha funzionato per me:

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

    Dove l’ item è l’ quadro cliente da ripristinare.

    Modo semplice senza tracciare alcuna modifica. Dovrebbe essere più veloce di guardare tutte le quadro.

     public void Rollback() { dataContext.Dispose(); dataContext= new MyEntities(yourConnection); } 
     // Undo the changes of all entries. foreach (DbEntityEntry entry in context.ChangeTracker.Entries()) { switch (entry.State) { // Under the covers, changing the state of an entity from // Modified to Unchanged first sets the values of all // properties to the original values that were read from // the database when it was queried, and then marks the // entity as Unchanged. This will also reject changes to // FK relationships since the original value of the FK // will be restored. case EntityState.Modified: entry.State = EntityState.Unchanged; break; case EntityState.Added: entry.State = EntityState.Detached; break; // If the EntityState is the Deleted, reload the date from the database. case EntityState.Deleted: entry.Reload(); break; default: break; } } 

    Ha funzionato per me. Tuttavia è necessario ricaricare i dati dal contesto per portare i vecchi dati. Fonte qui

    “Questo ha funzionato per me:

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

    Dove l’ item è l’entity framework cliente da ripristinare. ”


    Ho eseguito test con ObjectContext.Refresh in SQL Azure e “RefreshMode.StoreWins” genera una query sul database per ogni quadro e causa una perdita di prestazioni. Basato su microsoft documentation ():

    ClientWins: le modifiche alle proprietà apportate agli oggetti nel contesto dell’object non vengono sostituite con i valori dall’origine dati. Alla successiva chiamata a SaveChanges, queste modifiche vengono inviate all’origine dati.

    StoreWins: le modifiche alle proprietà apportate agli oggetti nel contesto dell’object vengono sostituite con i valori dall’origine dati.

    ClientWins non è una buona ideia neanche, perché l’triggerszione di .SaveChanges commetterà modifiche “scartate” all’origine dati.

    Non so ancora quale sia il modo migliore, perché l’eliminazione del contesto e la creazione di una nuova causa di un’eccezione con il messaggio: “Il provider sottostante non è riuscito all’apertura” quando provo a eseguire qualsiasi query su un nuovo contesto creato.

    Saluti,

    Henrique Clausing

    Per quanto mi riguarda, un metodo migliore per farlo è impostare EntityState.Unchanged su tutte le quadro su cui vuoi annullare le modifiche. Questo assicura che le modifiche vengano ripristinate su FK e che abbia una syntax un po ‘più chiara.

    Ho trovato che funziona bene nel mio contesto:

    Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);

    Questo è un esempio di ciò di cui parla Mrnka. Il metodo seguente sovrascrive i valori correnti di un’entity framework con i valori originali e non richiama il database. Facciamo questo usando la proprietà OriginalValues ​​di DbEntityEntry, e facciamo uso della riflessione per impostare i valori in modo generico. (Funziona come EntityFramework 5.0)

     ///  /// Undoes any pending updates ///  public void UndoUpdates( DbContext dbContext ) { //Get list of entities that are marked as modified List modifiedEntityList = dbContext.ChangeTracker.Entries().Where(x => x.State == EntityState.Modified).ToList(); foreach( DbEntityEntry entity in modifiedEntityList ) { DbPropertyValues propertyValues = entity.OriginalValues; foreach (String propertyName in propertyValues.PropertyNames) { //Replace current values with original values PropertyInfo property = entity.Entity.GetType().GetProperty(propertyName); property.SetValue(entity.Entity, propertyValues[propertyName]); } } } 

    Stiamo utilizzando EF 4, con il contesto dell’object legacy. Nessuna delle soluzioni di cui sopra ha risposto direttamente a questo per me, anche se è stata la risposta a lungo termine spingendomi nella giusta direzione.

    Non possiamo semplicemente disporre e ribuild il contesto perché alcuni degli oggetti che abbiamo in memoria (maledetto caricamento pigro !!) sono ancora collegati al contesto ma hanno figli che devono ancora essere caricati. In questi casi è necessario rimbalzare tutto su valori originali senza martellare il database e senza rilasciare la connessione esistente.

    Di seguito è la nostra soluzione a questo stesso problema:

      public static void UndoAllChanges(OurEntities ctx) { foreach (ObjectStateEntry entry in ctx.ObjectStateManager.GetObjectStateEntries(~EntityState.Detached)) { if (entry.State != EntityState.Unchanged) { ctx.Refresh(RefreshMode.StoreWins, entry.Entity); } } } 

    Spero che questo aiuti gli altri.

    Alcune buone idee sopra, ho scelto di implementare ICloneable e quindi un semplice metodo di estensione.

    Trovato qui: come faccio a clonare una lista generica in C #?

    Per essere usato come:

     ReceiptHandler.ApplyDiscountToAllItemsOnReciept(LocalProductsOnReciept.Clone(), selectedDisc); 

    In questo modo sono riuscito a clonare la mia lista di entity framework prodotto, applicare uno sconto a ciascun articolo e non dovermi preoccupare di annullare eventuali modifiche all’entity framework originale. Non c’è bisogno di parlare con DBContext e chiedere un aggiornamento o lavorare con ChangeTracker. Si potrebbe dire che non sto facendo pieno uso di EF6, ma questa è un’implementazione molto carina e semplice ed evita il successo di un DB. Non posso dire se questo abbia un impatto sulle prestazioni.