Mike
Mike

Reputation: 751

C# audit overriding SaveChanges() method. How to find out foreign keys of an entity and its value from table

I m overriding the SaveChange() method. What i want is that to log all changes made to an entity to database in simple text like "abc updated Name john to doe, ..." etc I have achieved the functionality but when there is a foreign key in an entity going to update like country_Id which points out the table Country it generates text like "abc updated Country_Id 1 to 3, ..." thats what I do not want it should be like this "abc updated Country Canada to Australia, ..."

So to achieve this it should know the foreign keys and its value

My Code is :

 public override int SaveChanges()
    {
        List<string> listChanges = new List<string>();
        List<string> listTable = new List<string>();

        var objectStateManager = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager;
        IEnumerable<ObjectStateEntry> changes =
            objectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added | EntityState.Deleted);


        foreach (ObjectStateEntry stateEntryEntity in changes)
        {

            var modifiedProperties = stateEntryEntity.GetModifiedProperties();
            foreach (var propName in modifiedProperties)
            {
                if (Convert.ToString(stateEntryEntity.OriginalValues[propName]) != Convert.ToString(stateEntryEntity.CurrentValues[propName]))
                {
                    listTable.Add(stateEntryEntity.EntityKey.EntitySetName);
                    listChanges.Add(propName + " From " + Convert.ToString(stateEntryEntity.OriginalValues[propName]) + " to " + Convert.ToString(stateEntryEntity.CurrentValues[propName]));

                }


                //System.Console.WriteLine("Property {0} changed from {1} to {2}",
                //     propName,
                //     stateEntryEntity.OriginalValues[propName],
                //     stateEntryEntity.CurrentValues[propName]);
            }
        }
         return base.SaveChanges();
    }

Upvotes: 6

Views: 1319

Answers (1)

orhun.begendi
orhun.begendi

Reputation: 937

There is a feature to achieve this, i used changetracker for track changes and log.You get every changes right before dispose your context so, for briefly you can build like this;

public override int SaveChanges()
        {
            foreach (var history in ChangeTracker.Entries()
                .Where(e => e.Entity is IModificationHistory && (e.State == EntityState.Added ||
                                                                 e.State == EntityState.Modified))
                .Select(e => e.Entity as IModificationHistory)
            )
            {
                history.DateModified = DateTime.Now;
                if (history.DateCreated == DateTime.MinValue)
                    history.DateCreated = DateTime.Now;
            }
            var result = base.SaveChanges();
            foreach (var history in ChangeTracker.Entries()
                .Where(e => e.Entity is IModificationHistory)
                .Select(e => e.Entity as IModificationHistory)
            )
                history.IsDirty = false;
            return result;
        }

Also you can specify your entry right before base.savechanges()

This is my history interface

 public interface IModificationHistory
    {
        DateTime DateModified { get; set; }
        DateTime DateCreated { get; set; }
        bool IsDirty { get; set; }
    }

Upvotes: 1

Related Questions