Получение всех изменений, внесенных в объект в Entity Framework
Есть ли способ получить все изменения, внесенные в объект в Entity Framework, прежде чем он сохранит все изменения. Причина этого заключается в том, что я хочу создать таблицу журналов в нашей базе данных клиентов:
так...
Есть ли способ получить текущие значения базы данных (старые) и новые значения (текущие) до сохранения изменений?
Если нет, как я могу достичь этого в общем виде, поэтому все мои модели просмотра могут наследовать от этого? (Я использую структуру MVVM + M)
Ответы
Ответ 1
Вы можете использовать ObjectContext ObjectStateManager, GetObjectStateEntry, чтобы получить объект ObjectStateEntry, который содержит свои исходные и текущие значения в OriginalValues и CurrentValues. Вы можете получить имена свойств, которые были изменены с помощью метода GetModifiedProperties.
Вы можете написать что-то вроде:
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]);
}
Ответ 2
Для EF5 вверх вы можете зарегистрировать свои изменения в методе 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();
}
Ответ 3
Я использую эту функцию расширения, которая предоставляет детали для изменяемого объекта, старые и новые значения, тип данных и ключ сущности.
Это проверено с помощью EF6.1 с использованием ObjectContext и использует log4net для вывода.
/// <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)));
}
}