2013-02-21 15 views
8

C'è un modo per ottenere l'Entità originale stessa da ChangeTracker (anziché solo i valori originali)?Come ottenere l'entità originale da ChangeTracker

Se il State è Modified, quindi suppongo che avrei potuto fare questo:

// Get the DbEntityEntry from the DbContext.ChangeTracker... 

// Store the current values 
var currentValues = entry.CurrentValues.Clone(); 

// Set to the original values 
entry.CurrentValues.SetValues(entry.OriginalValues.Clone()); 

// Now we have the original entity 
Foo entity = (Foo)entry.Entity; 

// Do something with it... 

// Restore the current values 
entry.CurrentValues.SetValues(currentValues); 

Ma questo non sembra molto bello, e sono sicuro che ci sono problemi con esso che non so riguardo ... c'è un modo migliore?

che sto utilizzando Entity Framework 6.

risposta

18

Override SaveChanges di DbContext o semplicemente accedere ChangeTracker dal contesto:

foreach (var entry in context.ChangeTracker.Entries<Foo>()) 
{ 
    if (entry.State == System.Data.EntityState.Modified) 
    { 
     // use entry.OriginalValues 
     Foo originalFoo = CreateWithValues<Foo>(entry.OriginalValues); 
    } 
} 

Ecco un metodo capace di creare una nuova entità con la valori originali Così tutte le entità devono avere un costruttore pubblico senza parametri, si può semplicemente costruire un'istanza con new:

private T CreateWithValues<T>(DbPropertyValues values) 
    where T : new() 
{ 
    T entity = new T(); 
    Type type = typeof(T); 

    foreach (var name in values.PropertyNames) 
    { 
     var property = type.GetProperty(name); 
     property.SetValue(entity, values.GetValue<object>(name)); 
    } 

    return entity; 
} 
+0

Mi può mancare una sottigliezza, ma credo di sapere come farlo (questo è solo ottenere i valori originali, giusto?) Voglio una rappresentazione fortemente tipizzata dell'entità originale - non solo i valori originali. – Eric

+0

@Eric si desidera avere un oggetto entità con i valori delle proprietà originali? –

+0

Sì, è corretto. Forse un modo per costruire un'entità dato un insieme di valori originali ... – Eric

1

Vorrei suggerire entità clone sulla materializzazione e di collegarli a secondo contesto per mantenere tutto il grafo degli oggetti originali (se ne avete bisogno ovviamente). Puoi renderli tutti riconoscibili modificando il modello T4.

5

Nice. Ecco una versione leggermente modificata che gestirà proprietà complesse:

public static TEntity GetOriginal<TEntity>(this DbContext ctx, TEntity updatedEntity) where TEntity : class 
    { 
     Func<DbPropertyValues, Type, object> getOriginal = null; 
     getOriginal = (originalValues, type) => 
      { 
       object original = Activator.CreateInstance(type, true); 
       foreach (var ptyName in originalValues.PropertyNames) 
       { 
        var property = type.GetProperty(ptyName); 
        object value = originalValues[ptyName]; 
        if (value is DbPropertyValues) //nested complex object 
        { 
         property.SetValue(original, getOriginal(value as DbPropertyValues, property.PropertyType)); 
        } 
        else 
        { 
         property.SetValue(original, value); 
        } 
       } 
       return original; 
      }; 
     return (TEntity)getOriginal(ctx.Entry(updatedEntity).OriginalValues, typeof(TEntity)); 
    } 
+0

Grazie a @Clemento. Ho avuto questo problema e ho impiegato molto tempo per recuperare i vecchi ... In primo luogo ho cercato di restituire oggetti totalmente scollegati. BUt ha avuto il suo insieme di problemi durante l'aggiornamento. Questo funziona, è necessario testare alcuni altri scenari anche se –

+0

Hey @Clement. Questo non idrata le proprietà di navigazione. Qualche indizio? –

+0

Non sono sicuro, non ho provato con le proprietà del nav. Poiché utilizza Activator.CreateInstance, non mi aspetto che il carico lazy delle proprietà di navigazione funzioni (poiché si basa su un tipo di proxy di runtime generato da EF). Potresti essere in grado di modificare questo codice per gestirli ... – Clement

-1

Lavorando con EF 6 i usato il seguente codice per ottenere il POCO tipo di entità sottostante dal tipo di proxy,

var entityType = ObjectContext.GetObjectType(dbEntitymodifiedEntry.Entity.GetType()); 

ObjectContext.GetObjectType: Return il POCO dall'oggetto proxy

+0

Questo restituisce solo un tipo. Non ho potuto ottenere i valori originali. –

Problemi correlati