We have a custom value converter for being able to store a JsonBlob. This works if value in the DB is a string / json string but if the value is null the Deserialize function is never hit. Is there a way to change this? This causes an issue because we would prefer to init an empty collection if there is no value.
The Converter
public class JsonStringConvertor<T> : ValueConverter<T, string> where T : class, new()
{
public JsonStringConvertor(ConverterMappingHints mappingHints = null)
: base(convertToProviderExpression, convertFromProviderExpression, mappingHints) { }
//Work around to dynamically create a ValueComparer<T>. Called using reflection
public ValueComparer<T> CreateValueComparer()
{
var comparer = new ValueComparer<T>
(
(l, r) => Serialize(l) == Serialize(r),
v => v == null ? 0 : Serialize(v).GetHashCode(),
v => Deserialize<T>(Serialize(v))
);
return comparer;
}
private static readonly Expression<Func<T, string>> convertToProviderExpression = v => Serialize(v);
private static readonly Expression<Func<string, T>> convertFromProviderExpression = v => Deserialize<T>(v) ?? new T();
private static string Serialize<TObj>(TObj t) => JsonConvert.SerializeObject(t, EntityFrameworkJson.SerializerSettings);
private static TVal Deserialize<TVal>(string s) => JsonConvert.DeserializeObject<TVal>(s, EntityFrameworkJson.SerializerSettings);
}
Usage
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Model
.GetEntityTypes()
.SelectMany(t => t.ClrType.GetProperties()
.Select(p => new
{
DeclaringEntityType = t.ClrType,
Property = p
}))
.Where(t => GetAttribute<JsonDataAttribute>(t.Property) != null)
.ForEach(t =>
{
//had to use reflection api to get all JsonData attributes, so now we reconstruct the EF PropertyBuilder
var propBuilder = modelBuilder.Entity(t.DeclaringEntityType).Property(t.Property.Name);
//Use old EF6 Naming Convention _Json
var identifier = StoreObjectIdentifier.Create(propBuilder.Metadata.DeclaringEntityType, StoreObjectType.Table);
if (identifier != null)
{
var propName = propBuilder.Metadata.GetColumnName(identifier.Value);
propBuilder.Metadata.SetColumnName(propName + "_Json");
}
//Setup Converter and Comparer
var converterType = typeof(JsonStringConvertor<>).MakeGenericType(t.Property.PropertyType);
var converter = (ValueConverter) Activator.CreateInstance(converterType, (object) null);
var comparerFunc = converter?.GetType().GetMethod("CreateValueComparer");
if (comparerFunc is {})
{
var comparer = (ValueComparer) comparerFunc.Invoke(converter, null);
propBuilder.Metadata.SetValueComparer(comparer);
}
propBuilder.HasConversion(converter);
propBuilder.Metadata.SetValueConverter(converter);
});
Thought it might be the comparer but it still doesn't work when not using the comparer. What i found during testing is that if the value in the database is null then the converter does not run. If i update it to an empty string it works.
we're using Entity Framework Core 5.0.1
question from:
https://stackoverflow.com/questions/65625770/ef-core-value-converter-does-not-run-when-db-value-is-null 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…