2010-07-16 19 views
35

¿Hay alguna forma de obtener todos los cambios realizados en un objeto en Entity Framework antes de guardar todos los cambios? La razón de esto es que quiero para crear una tabla de registro en nuestra base de datos clientes:Obtener todos los cambios realizados en un objeto en Entity Framework

así que ...

¿Hay una manera de obtener los valores de base de datos actual (antigua) y los nuevos valores (actual) antes de guardar los cambios?

Si no es así, ¿cómo puedo lograr esto de una manera genérica, por lo que todos mis Ver modelos pueden heredar de esto? (Estoy usando la estructura MVVM + M)

+0

Puede resolverlo con SP y desencadenantes en la base de datos. –

Respuesta

44

Puede utilizar ObjectContext de ObjectStateManager,GetObjectStateEntry para obtener un objeto de ObjectStateEntry, que mantiene sus valores originales y actuales en las propiedades OriginalValues y CurrentValues. Puede obtener los nombres de las propiedades que cambiaron utilizando el método GetModifiedProperties.

Puede escribir algo como:

var myObjectState=myContext.ObjectStateManager.GetObjectStateEntry(myObject); 
var modifiedProperties=myObjectState.GetModifiedProperties(); 
foreach(var propName in modifiedProperties) 
{ 
    Console.WriteLine("Property {0} changed from {1} to {2}", 
     propName, 
     myObjectState.OriginalValues[propName], 
     myObjectState.CurrentValues[propName]); 
} 
+1

Eche un vistazo a este artículo [Audit Trail Using EF ObjectContext] (http://www.codeproject.com/Articles/34491/Implementing-Audit-Trail-using-Entity-Framework-Pa) –

+0

Está utilizando los mismos métodos así como –

+0

'ApplicationDbContext' no contiene una definición para 'ObjectStateManager' – Sam

20

Para EF5 hacia arriba se puede registrar sus método como este cambio en las SaveChanges():

public override int SaveChanges() 
    { 

     var changes = from e in this.ChangeTracker.Entries() 
         where e.State != System.Data.EntityState.Unchanged 
         select e; 

     foreach (var change in changes) 
     { 
      if (change.State == System.Data.EntityState.Added) 
      { 
       // Log Added 
      } 
      else if (change.State == System.Data.EntityState.Modified) 
      { 
       // Log Modified 
       var item = change.Cast<IEntity>().Entity; 
       var originalValues = this.Entry(item).OriginalValues; 
       var currentValues = this.Entry(item).CurrentValues; 

       foreach (string propertyName in originalValues.PropertyNames) 
       { 
        var original = originalValues[propertyName]; 
        var current = currentValues[propertyName]; 

        if (!Equals(original, current)) 
        { 
         // log propertyName: original --> current 
        } 
       } 

      } 
      else if (change.State == System.Data.EntityState.Deleted) 
      { 
       // log deleted 
      } 
     } 
     // don't forget to save 
     base.SaveChanges(); 
    } 
5

puedo utilizar esta función de extensión que proporciona detalles sobre el la entidad que se cambia, los valores antiguos y nuevos, el tipo de datos y la clave de entidad.

Esto se prueba con EF6.1 utilizando ObjectContext y usa log4net para la salida.

/// <summary> 
    /// dump changes in the context to the debug log 
    /// <para>Debug logging must be turned on using log4net</para> 
    /// </summary> 
    /// <param name="context">The context to dump the changes for</param> 
    public static void DumpChanges(this ObjectContext context) 
    { 
     context.DetectChanges(); 
     // Output any added entries 
     foreach (var added in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added)) 
     { 
      Log.DebugFormat("{0}:{1} {2} {3}", added.State, added.Entity.GetType().FullName, added.Entity.ToString(), string.Join(",", added.CurrentValues.GetValue(1), added.CurrentValues.GetValue(2))); 
     } 
     foreach (var modified in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)) 
     { 
      // Put original field values into dictionary 
      var originalValues = new Dictionary<string,int>(); 
      for (var i = 0; i < modified.OriginalValues.FieldCount; ++i) 
      { 
       originalValues.Add(modified.OriginalValues.GetName(i), i); 
      } 
      // Output each of the changed properties. 
      foreach (var entry in modified.GetModifiedProperties()) 
      { 
       var originalIdx = originalValues[entry]; 
       Log.DebugFormat("{6} = {0}.{4} [{7}][{2}] [{1}] --> [{3}] Rel:{5}", 
        modified.Entity.GetType(), 
        modified.OriginalValues.GetValue(originalIdx), 
        modified.OriginalValues.GetFieldType(originalIdx), 
        modified.CurrentValues.GetValue(originalIdx), 
        modified.OriginalValues.GetName(originalIdx), 
        modified.IsRelationship, 
        modified.State, 
        string.Join(",", modified.EntityKey.EntityKeyValues.Select(v => string.Join(" = ", v.Key, v.Value)))); 
      } 
     } 
     // Output any deleted entries 
     foreach (var deleted in context.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted)) 
     { 
      Log.DebugFormat("{1} {0} {2}", deleted.Entity.GetType().FullName, deleted.State, string.Join(",", deleted.CurrentValues.GetValue(1), deleted.CurrentValues.GetValue(2))); 
     } 
    } 
+0

La pregunta original era cómo obtener cambios en una entidad, no los cambios realizados en el contexto. –

Cuestiones relacionadas