2012-05-10 18 views
8

Estaba trabajando con servicios de RIA donde ObjectContext tiene el método RejectChanges(). Sin embargo, ahora estoy trabajando con EF 4.4 en una aplicación de escritorio y no puedo encontrar ese método. Entonces, mi pregunta es: en un escenario en el que le permitía al usuario hacer operaciones de CrUD por lotes en la colección, ¿cómo iba a revertir todos los cambios? Podría continuar recreando el contexto y recuperando los datos nuevamente, pero eso suena muy innecesario si necesito revertir los cambios a 1-2 entidades.DbContext y RejectChanges

Entonces, ¿cuál es la mejor manera de rechazar los cambios? Y también, ¿cómo sabemos si el contexto está haciendo algo (IsBusy)?

Respuesta

11

EF no tiene ninguna operación directa de "rechazo de cambios". Puede acceder a las entradas de entidades en ChangeTracker/ObjectStateManager y sobrescribir los valores actuales con los valores originales para las entidades modificadas. También puede separar entidades añadidas y volver a cambiar las entidades eliminadas sin cambios, pero todas funcionarán principalmente si usted (o EF internamente) no cambió el estado de ninguna asociación (relación) independiente. Si también trabajas con relaciones, todo puede ser mucho más complicado porque también debes revertir las relaciones; en tal caso, es más sencillo volver a cargar los datos.

Para revertir los cambios en la API DbContext puede probar esto:

foreach (var entry in context.ChangeTracker 
          .Entries<YourEntityType>() 
          .Where(e => e.State == EntityState.Modified)) 
{ 
    entry.CurrentValues.SetValues(entry.OriginalValues); 
} 

En este caso creo que el principal problema es la forma en cómo se trabaja con entidades - se permiten cambios de datos en tiempo real y EF hace su lógica Detrás para mantener la coherencia de los datos cuando se realizan cambios, pero más tarde decide que esos cambios no se guardarán. En este caso, usted debe hacer uno de los siguientes:

  • Descartar los datos modificados y volver a cargar conjunto de datos entero (por recrear el contexto)
  • independiente esta lógica a no funcionar en datos en tiempo real y empuje la modificación de datos de contexto EF solamente cuando la modificación es realmente confirmada

El contexto está haciendo algo si usted lo dice para hacer algo. Nunca se vuelve ocupado en sí mismo.

+0

Recrear el contexto sería una buena solución. Sin embargo, estaba teniendo problemas con la sincronización de datos relacionados. Un ejemplo sería que tenía CRUD en CollectionA en ViewA, y CRUD en COllectionB en ViewB. CollectionB también hace referencia a CollectionA. Entonces, si tengo 2 objetos Context, tanto para CollectionA como CollectionB, ¿cómo sincronizaría ViewB, si cambio CollectionA en ViewA? Cuando se tiene un contexto, todo es sincronización, ya que en realidad estamos trabajando en una única colección de instancia A, no en dos. Recrear Contexto "global" crearía un caos. :) ¿Cometí un error al usar el contexto "global"? – Goran

+0

En cuanto al "Ocupado", me preocupaba lo que sucedería si ejecutaba una carga en modo sincronizado, y luego intentaba emitir otra carga, ¿mientras que antes no terminaba? De esta forma podría verificar si está "Ocupado", así podría poner en cola una nueva Carga. – Goran

+0

+1 para notar lo que la mayoría de la gente parece perder. las relaciones: es posible tener cambios rastreados que no se recogerán simplemente mirando a través de la colección de entradas para el estado! = Sin cambios. (EF v6.) – mwardm

1

Esto funciona para mí:

public void RejectChanges() { 
    var context = ((IObjectContextAdapter)this).ObjectContext; 
    foreach (var change in this.ChangeTracker.Entries()) { 
     if (change.State == EntityState.Modified) { 
      context.Refresh(RefreshMode.StoreWins, change.Entity); 
     } 
     if (change.State == EntityState.Added) { 
      context.Detach(change.Entity); 
     } 
    } 
} 

este = DbContext en este caso

+1

¿Qué pasa con las entidades eliminadas? Además, ¿cómo obtendría datos nuevos para las entidades que otros usuarios han cambiado, no usted? – Goran

2

Sé que esto es una cuestión de edad. Sin embargo, ninguna de las respuestas se ajusta a mi situación. Necesitaba rechazar los cambios en solo 1 entidad en una colección. Esto es lo que funcionó para mí:

var objectContext = (myDbContext as IObjectContextAdapter).ObjectContext; 
    objectContext.Refresh(RefreshMode.StoreWins, partMaster); 
+0

Aunque la pregunta era acerca de los cambios en la recopilación, no en una sola entidad, ¿no veo cómo ninguna de las respuestas lo ayudó? La respuesta justo arriba de la suya (TheSoul75) hace exactamente lo mismo que su sugerencia, solo que lo hace para todos los artículos en la colección. – Goran

+0

Goran, si se rechazaran todos los cambios en la colección, mis datos no serían válidos. Solo uno de los elementos de la colección debe volver a los valores originales. Necesito un enfoque más granular. Sé que a veces los demás también necesitan control granular. Publiqué la respuesta para ayudar a otros que tienen requisitos similares. – Tarzan

+1

Bueno, no usas foreach, pero esencialmente estás usando la misma tecnología (Refresh with StoreWins), así que no veo el valor agregado en tu respuesta, ya que acabas de quitar el ciclo. – Goran

11
public void RejectChanges() 
     { 
      foreach (var entry in ChangeTracker.Entries()) 
      { 
       switch (entry.State) 
       { 
        case EntityState.Modified: 
         { 
          entry.CurrentValues.SetValues(entry.OriginalValues); 
          entry.State = EntityState.Unchanged; 
          break; 
         } 
        case EntityState.Deleted: 
         { 
          entry.State = EntityState.Unchanged; 
          break; 
         } 
        case EntityState.Added: 
         { 
          entry.State = EntityState.Detached; 
          break; 
         } 
       } 
      } 
     } 
+0

Esta parece ser la única respuesta que maneja todos los estados sin golpear la base de datos. +1 – Dan

+0

¿Qué sucede si solo cambio las referencias? M: n especialmente puro cuando no hay ninguna propiedad de clave externa afectada? – springy76

0

Esto puede ser una respuesta de edad, pero útil para cualquier nuevo programa de visitas .... La función de recarga que se recargue el objeto de la fuente de datos y sobrescribir los cambios existentes y la entidad recién cargada tendrá un estado sin cambios.

public static void UndoEntityChanges(object Entity) 
{ 
    <EFModelContainer>.Entry(Entity).Reload(); 
} 
Cuestiones relacionadas