Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON serialization Value Conversion not tracking changes with EF Core

I am using an EF Core value conversion.

https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions

I wrote a JSON serializer converter as follows:

private static ValueConverter<T, String> JsonValueConverter<T>()
{
    ValueConverter<T, String> jsonConverter = new ValueConverter<T, String>(
        v => JsonConvert.SerializeObject(v),
        v => JsonConvert.DeserializeObject<T>(v));
    return jsonConverter;
}

Implemented in the app with:

protected override void OnModelCreating(ModelBuilder mb)
{    
   ...
   mb.Entity<MyObject>()
     .Property(p => p.MySerializableObject)
     .HasConversion(JsonValueConverter<MySerializableObject>());
   ...
}

It works.

However, when you make changes to a property inside the serialized object, EF Core change tracking does not pick up changes to MySerializableObject.

I assume there is some way to force this on the object level. I have attempted to implement IEqualityComparer on MySerializableObject but change tracking didn't start working.

like image 330
Dave Loukola Avatar asked Oct 29 '18 17:10

Dave Loukola


1 Answers

I was able to get change tracking to kick in by adding a ValueConverter and a ValueComparer to the Metadata of the property, however, my comparer is probably very inefficient. If anyone has suggestions on performance tuning for this, it would be much appreciated.

mb.Entity<MyObject>().Property(p => .MySerializableObject).HasJsonConversion();

With the new HasJsonConversion extension method

public static class ValueConversionExtensions
{
    public static PropertyBuilder<T> HasJsonConversion<T>(this PropertyBuilder<T> propertyBuilder)
    {           
        ValueConverter<T, String> converter = new ValueConverter<T, String>(
            v => JsonConvert.SerializeObject(v),
            v => JsonConvert.DeserializeObject<T>(v));

        ValueComparer<T> comparer = new ValueComparer<T>(
            (l, r) => JsonConvert.SerializeObject(l) == JsonConvert.SerializeObject(r),
            v => v == null ? 0 : JsonConvert.SerializeObject(v).GetHashCode(),
            v => JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(v)));

        propertyBuilder.HasConversion(converter);
        propertyBuilder.Metadata.SetValueConverter(converter);
        propertyBuilder.Metadata.SetValueComparer(comparer);            

        return propertyBuilder;
    }        
}
like image 132
Dave Loukola Avatar answered Nov 09 '22 10:11

Dave Loukola