esta podría ser una pregunta trivial, pero: dado que ADO.NET entity framework rastrea automáticamente los cambios (en las entidades generadas) y, por lo tanto, mantiene los valores originales, ¿cómo puedo revertir los cambios realizados en los objetos de la entidad?
Tengo un formulario que permite al usuario editar un conjunto de entidades "Cliente" en una vista de cuadrícula.
Ahora tengo dos botones "Aceptar" y "Revertir": si se hace clic en "Aceptar", llamo Context.SaveChanges()
y los objetos modificados se vuelven a escribir en la base de datos. Si se hace clic en "Revertir", me gustaría que todos los objetos obtengan sus valores de propiedad originales. ¿Cuál sería el código para eso?
Gracias
fuente
Context.Refresh()
es un contraejemplo a su afirmación de que no hay operación de reversión? UsarRefresh()
parece un mejor enfoque (es decir, más fácilmente dirigido a entidades específicas) que eliminar el contexto y perder todos los cambios registrados.Consulta ChangeTracker de DbContext para elementos sucios. Establezca el estado de los elementos eliminados como sin cambios y los elementos agregados como separados. Para los elementos modificados, utilice los valores originales y establezca los valores actuales de la entrada. Finalmente, establezca el estado de la entrada modificada como sin cambios:
fuente
State
en EntityState.Unchanged también anulará todos los valores, porOriginal Values
lo que no es necesario llamar alSetValues
método.De acuerdo con MSDN :
Tenga en cuenta que volver a través de la solicitud a la base de datos tiene algunos inconvenientes:
fuente
Esto funcionó para mí:
Dónde
item
se revertirá la entidad cliente.fuente
Manera fácil sin realizar un seguimiento de los cambios. Debería ser más rápido que mirar todas las entidades.
fuente
Rollback
procedimiento anterior , lo que lo convierte en una opción mucho mejor si uno quiere revertir el estado completo de la base de datos. Rollback podría elegir bien.50ms+0*n= 50ms
. O (n) significa que el rendimiento está influenciado por la cantidad de objetos ... el rendimiento es quizás2ms+0.5ms*n
... así que debajo de 96 objetos sería más rápido, pero el tiempo aumentaría linealmente con la cantidad de datos.Funcionó para mí. Sin embargo, debe volver a cargar sus datos desde el contexto para traer los datos antiguos. Fuente aquí
fuente
"Esto funcionó para mí:
¿Dónde
item
se revertirá la entidad cliente? ".He hecho pruebas con ObjectContext.Refresh en SQL Azure, y "RefreshMode.StoreWins" dispara una consulta contra la base de datos para cada entidad y causa una pérdida de rendimiento. Basado en documentación de microsoft ():
ClientWins: los cambios de propiedad realizados en los objetos en el contexto del objeto no se reemplazan con valores del origen de datos. En la próxima llamada a SaveChanges, estos cambios se envían a la fuente de datos.
StoreWins: los cambios de propiedad realizados en los objetos en el contexto del objeto se reemplazan con valores del origen de datos.
ClientWins tampoco es una buena idea, porque la activación de .SaveChanges enviará cambios "descartados" a la fuente de datos.
No sé cuál es la mejor manera todavía, porque eliminar el contexto y crear uno nuevo genera una excepción con el mensaje: "El proveedor subyacente falló al abrirse" cuando intento ejecutar cualquier consulta en un nuevo contexto creado.
Saludos,
Henrique Clausing
fuente
En cuanto a mí, el mejor método para hacerlo es establecer
EntityState.Unchanged
en cada entidad en la que desea deshacer los cambios. Esto asegura que los cambios se reviertan en FK y tiene una sintaxis un poco más clara.fuente
Encontré que esto funciona bien en mi contexto:
Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);
fuente
DbContext.SaveChanges()
, pero no devolverá los valores de la entidad a los valores originales. Y si el estado de la entidad se modifica a partir de un cambio posterior, ¿posiblemente todas las modificaciones anteriores se mantendrán al guardar?Este es un ejemplo de lo que habla Mrnka. El siguiente método sobrescribe los valores actuales de una entidad con los valores originales y no llama a la base de datos. Hacemos esto haciendo uso de la propiedad OriginalValues de DbEntityEntry y usamos la reflexión para establecer valores de una manera genérica. (Esto funciona a partir de EntityFramework 5.0)
fuente
Estamos usando EF 4, con el contexto de objetos heredados. Ninguna de las soluciones anteriores me respondió directamente a esto, aunque sí lo hizo a largo plazo empujándome en la dirección correcta.
No podemos simplemente deshacernos y reconstruir el contexto porque algunos de los objetos que tenemos en la memoria (¡¡maldita sea la carga diferida !!) todavía están adjuntos al contexto pero tienen hijos que aún no se han cargado. Para estos casos, debemos restablecer todo a los valores originales sin martillar la base de datos y sin eliminar la conexión existente.
A continuación se muestra nuestra solución a este mismo problema:
Espero que esto ayude a otros.
fuente
Algunas buenas ideas anteriores, elegí implementar ICloneable y luego un método de extensión simple.
Encontrado aquí: ¿Cómo clono una lista genérica en C #?
Para ser utilizado como:
De esta manera pude clonar mi lista de entidades de productos, aplicar un descuento a cada artículo y no tener que preocuparme por revertir los cambios en la entidad original. No es necesario hablar con DBContext y solicitar una actualización o trabajar con ChangeTracker. Podría decirse que no estoy haciendo un uso completo de EF6, pero esta es una implementación muy agradable y simple y evita un golpe de DB. No puedo decir si esto tiene un impacto en el rendimiento.
fuente