Получение всех изменений, внесенных в объект в Entity Framework - PullRequest
41 голосов
/ 16 июля 2010

Есть ли способ получить все изменения, внесенные в объект в Entity Framework, прежде чем он сохранит все изменения. Причина в том, что я хочу создать таблицу журналов в нашей базе данных клиентов:

так ...

Есть ли способ получить текущие значения базы данных (старые) и новые значения (текущие) до сохранения изменений?

Если нет, как я могу добиться этого общим способом, чтобы все мои модели представления могли наследовать от этого? (Я использую структуру MVVM + M)

Ответы [ 4 ]

56 голосов
/ 16 июля 2010

Вы можете использовать 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]);
}
34 голосов
/ 23 сентября 2015

Для 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();
    }
8 голосов
/ 24 октября 2015

Я использую эту функцию расширения, которая предоставляет подробную информацию об изменяемой сущности, старых и новых значениях, типе данных и ключе сущности.

Это проверено с 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)));
        }
    }
0 голосов
/ 14 марта 2018

Вы можете реализовать это на C # несколькими способами.Следующий код демонстрирует один из них.

Требования

Установки

  • PM> Установочный пакет DevExpressMvvm -Version 17.1.6
  • PM> Установочный пакет System.ValueTuple -Version 4.4.0

Пример

using DevExpress.Mvvm;
using DevExpress.Mvvm.Native;
using System;
using System.Linq;
using System.ComponentModel;
using System.Collections.Generic;

namespace TrackingPropertyManagerApp
{
    public class Member : BindableBase
    {
        public Member()
        {
            PropertyManager = new TrackingPropertyManager();
        }

        private string _MemberProperty;
        [DisplayName("Your property description")]
        public string MemberProperty
        {
            get { return _MemberProperty; }
            set { SetProperty(ref _MemberProperty, value, () => MemberProperty); }
        }

        private TrackingPropertyManager PropertyManager { get; }
        protected override PropertyManager CreatePropertyManager() => PropertyManager;

        public IEnumerable<(string property, object original, object changed)> GetChangedProperties()
            => from changes in PropertyManager.ChangeTracker
               where changes.Value.wasChanged
               select (property: changes.Key, original: changes.Value.original, changed: changes.Value.changed);

        private class TrackingPropertyManager : PropertyManager
        {
            internal IDictionary<string, (object original, bool wasChanged, object changed)> ChangeTracker = new Dictionary<string, (object, bool, object)>();
            protected override bool SetPropertyCore<T>(ref T storage, T value, string propertyName)
            {
                if (ChangeTracker.TryGetValue(propertyName, out (object original, bool wasChanged, object changed) changeInfo))
                {
                    if (!EqualityComparer<T>.Default.Equals(storage, value))
                    {
                        ChangeTracker[propertyName] = (changeInfo.original, true, value);
                    }
                }
                else
                {
                    ChangeTracker[propertyName] = (value, false, null);
                }
                return base.SetPropertyCore(ref storage, value, propertyName);
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var member = new Member();
            member.MemberProperty = "first value";
            member.MemberProperty = "second value";
            member.MemberProperty = "last value";

            var changes = member.GetChangedProperties().ToArray();
            var type = typeof(Member);
            foreach (var (property, original, changed) in changes)
            {
                var propertyInfo = type.GetProperty(property);
                if (propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault() is DisplayNameAttribute displayAttribute)
                {
                    Console.WriteLine($"{ displayAttribute.DisplayName }: old='{ original }' new='{ changed }'");
                }
            }
            Console.ReadLine();
        }
    }
}

Вывод

Описание вашего свойства: old = 'first value' new = 'last value'

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...