Per scopi di controllo / cronologia, sto utilizzando il tracker delle modifiche di Entity Framework per determinare, prima di scrivere le modifiche, cosa è cambiato e serializzare le modifiche. Posso ottenere le entità modificate chiamando this.ChangeTracker.Entries()
nella derivata DbContext
e osservando i valori per qualsiasi cosa contrassegnata EntityState.Added
, EntityState.Deleted
o EntityState.Modified
. Tutto funziona alla grande.
Il mio problema è che questo metodo non funziona per tenere traccia delle modifiche alle raccolte di oggetti EF (ad esempio, una proprietà ICollection<Person>
su un oggetto PersonGroup
).
Sono sicuro che il contesto EF deve tracciare questo in qualche modo - in che altro modo funzionerebbe l'aggiornamento del database, dopo tutto? Ma è disponibile per me?
Quello che stai cercando è il monitoraggio delle modifiche delle relazioni. Puoi trovarlo in ObjectStateManager
del ObjectContext
sottostante, ecco come ottieni tutte le relazioni aggiunte:
//you need to call DetectChanges
((IObjectContextAdapter)context).ObjectContext.DetectChanges();
var addedRelations = ((IObjectContextAdapter)context).ObjectContext
.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
.Where(e=>e.IsRelationship).ToList();
Si scopre che è possibile ottenere le relazioni con questo codice (presupponendo che sia in esecuzione all'interno del derivato DbContext
):
((IObjectContextAdapter) this).ObjectContext.ObjectStateManager
.GetObjectStateEntries(EntityState.Added)
.Where(e => e.IsRelationship)
.Select(r => new {EntityKeyInfo = r.CurrentValues[0],
CollectionMemberKeyInfo = r.CurrentValues[1], r.State});
Ovviamente è possibile modificare questo in base a ciò che ti serve e spetta a te fare qualcosa di utile con esso. Le prime due voci CurrentValues
rappresentano oggetti EntityKey che ti permetteranno di ottenere gli ID delle entità in questione.
Se vuoi gestire entità cancellate, questo non funzionerà e dovrai usare la riflessione. Invece di CurrentValues[0]
e CurrentValues[1]
puoi guardare le proprietà interne Key0
e Key1
, che sono definite in una classe interna a cui non puoi accedere in fase di compilazione. r.GetType().GetProperty("Key0", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(r, new object[0])
: r.GetType().GetProperty("Key0", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(r, new object[0])
. Si noti che questo probabilmente non è un uso previsto e potrebbe saltare in aria ogni volta.