Efcore: ChangeTracker EnityEntry: detect if a single property has changed and get old and new values for logging

Created on 21 Jul 2017  路  1Comment  路  Source: dotnet/efcore

Sorry for posting here since this is rather a question than an issue report.

I developed kind of an automatic database change logger which logs the changes to the database after each DbContext.SaveChanges. Therefore I used the ChangeTracker and the containing EntityEntry.State to check if an Entity has changed and log the values. Actually it builds a list of strings which then can be logged as the user wants.
It works perfectly for States ADDED and DELETED.

Describe what is not working as expected.

My problem is the state MODIFIED because I can't figure out if a Property withing the EntityEntry has changed or not.
In case of Modified I want to log something like
MODIFIED EntityClassName(fieldname: [oldVal > newVal], nextFieldName: valueThatHasntChanged)

My code structure:
Before saveChanges I clone() all the original values of the changed EntityEntry items and store them into PropertyValues _orginalValues. Now after save changes I create the logs.

Why I use two steps is because on added I want the DB generated ids to be logged (which I can't do before save changes) and in case of deleted I want to make sure that the values that were deleted are still available to logs.

The code for that looks like:

```C#
case EntityState.Modified:
for (int i = 0; i < _originalValues.Properties.Count; i++)
{
prop = _originalValues.Properties[i];
sb.Append(prop.Name);
sb.Append(": ");

        //var orig = _originalValues[prop.Name];
        //var cur = _entry.CurrentValues[prop.Name];
        //var curOrig = _entry.OriginalValues[prop.Name];

        //bool changed = orig != cur;
        //bool changed2 = cur != curOrig;


        if (_originalValues[prop.Name] != _entry.CurrentValues[prop.Name])
        {
            // value has changed
            sb.Append("[");
            sb.Append((_originalValues[prop.Name] != null) ? _originalValues[prop.Name] : "null");
            sb.Append(" > ");
            sb.Append((_entry.CurrentValues[prop.Name] != null) ? _entry.CurrentValues[prop.Name] : "null");
            sb.Append("]");
        }
        else
        {
            // value hasn't changed
            sb.Append((_entry.CurrentValues[prop.Name] != null) ? _entry.CurrentValues[prop.Name] : "null");
        }


        if (i < _originalValues.Properties.Count - 1) sb.Append(", ");
    }
    sb.Append(")");
    break;

```

Whats not working:
I always get the new CurrentValues and never the old ones.
I can't detect if a property has changed. is always true:
(_originalValues[prop.Name] != _entry.CurrentValues[prop.Name]

Further technical details

EF Core version: 1.1.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer 1.1.0
Operating system: Win 7 x64
IDE: Visual Studio 2015

closed-question

Most helpful comment

@MontyGvMC When you have entities that are tracked by the context (e.g. from a query) and then make changes to those entities, EF keeps track of both the original values and which properties have changed. So, for example, this code:
```C#
using (var context = new BlogsContext())
{
var blog = context.Blogs.First();

blog.Title = "Two";

foreach (var entry in context.Entry(blog).Properties)
{
    Console.WriteLine(
        $"Property '{entry.Metadata.Name}'" +
        $" is {(entry.IsModified ? "modified" : "not modified")} " +
        $"Current value: '{entry.CurrentValue}' " +
        $"Original value: '{entry.OriginalValue}'");
}

}

gives this output:

Property 'Id' is not modified Current value: '1' Original value: '1'
Property 'Title' is modified Current value: 'Two' Original value: 'One'
```

It's not completely clear to me how the rest of your code is structured, but hopefully you can use the same ideas to gather the information you need.

>All comments

@MontyGvMC When you have entities that are tracked by the context (e.g. from a query) and then make changes to those entities, EF keeps track of both the original values and which properties have changed. So, for example, this code:
```C#
using (var context = new BlogsContext())
{
var blog = context.Blogs.First();

blog.Title = "Two";

foreach (var entry in context.Entry(blog).Properties)
{
    Console.WriteLine(
        $"Property '{entry.Metadata.Name}'" +
        $" is {(entry.IsModified ? "modified" : "not modified")} " +
        $"Current value: '{entry.CurrentValue}' " +
        $"Original value: '{entry.OriginalValue}'");
}

}

gives this output:

Property 'Id' is not modified Current value: '1' Original value: '1'
Property 'Title' is modified Current value: 'Two' Original value: 'One'
```

It's not completely clear to me how the rest of your code is structured, but hopefully you can use the same ideas to gather the information you need.

Was this page helpful?
0 / 5 - 0 ratings