I was trying to accomplish the conversion dynamically across all of the models I have in my project:
DbContext.cs
protected override void OnModelCreating(ModelBuilder modelBuilder) { var entityTypes = modelBuilder.Model.GetEntityTypes().ToList(); foreach (var entityType in entityTypes) { foreach (var property in entityType.ClrType.GetProperties().Where(x => x != null && x.GetCustomAttribute<HasJsonConversionAttribute>() != null)) { modelBuilder.Entity(entityType.ClrType) .Property(property.PropertyType, property.Name) .HasJsonConversion(); } } base.OnModelCreating(modelBuilder); }
Then created a data annotation attribute to mark my fields in my model as "Json"
public class HasJsonConversionAttribute : Attribute {}
This is my extension method used to convert the Json to object and back to Json
public static class SqlExtensions { public static PropertyBuilder HasJsonConversion(this PropertyBuilder propertyBuilder) { ParameterExpression parameter1 = Expression.Parameter(propertyBuilder.Metadata.ClrType, "v"); MethodInfo methodInfo1 = typeof(Newtonsoft.Json.JsonConvert).GetMethod("SerializeObject", types: new Type[] { typeof(object) }); MethodCallExpression expression1 = Expression.Call(methodInfo1 ?? throw new Exception("Method not found"), parameter1); ParameterExpression parameter2 = Expression.Parameter(typeof(string), "v"); MethodInfo methodInfo2 = typeof(Newtonsoft.Json.JsonConvert).GetMethod("DeserializeObject", 1, BindingFlags.Static | BindingFlags.Public, Type.DefaultBinder, CallingConventions.Any, types: new Type[] { typeof(string) }, null)?.MakeGenericMethod(propertyBuilder.Metadata.ClrType) ?? throw new Exception("Method not found"); MethodCallExpression expression2 = Expression.Call(methodInfo2, parameter2); var converter = Activator.CreateInstance(typeof(ValueConverter<,>) .MakeGenericType(propertyBuilder.Metadata.ClrType, typeof(string)), new object[] { Expression.Lambda( expression1,parameter1), Expression.Lambda( expression2,parameter2), (ConverterMappingHints) null }); propertyBuilder.HasConversion(converter as ValueConverter); return propertyBuilder; } }
For simplicity I'm using this User model:
public class User : IEntityTypeConfiguration<User> { public void Configure(EntityTypeBuilder<User> builder) { // Apply some settings defined in custom annotations in the model properties //builder.ApplyCustomAnnotationsAndConfigs(this); } [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public string Username { get; set; } [HasJsonConversion] public List<LocalizedName> Values { get; set; } }
and This is the class that I want to convert to and from JSON:
public class LocalizedName { public string Value { get; set; } public string Code { get; set; } }
Now here's the problem I'm facing, it keeps on detecting LocalizedName
object as another model
that doesn't have a Key
and throws an error telling me to add a Key/PK
even though this is not flagged as a model.
Now if I execute this from the User -> Configure()
it will work BUT it'll show me other issues like the model loses its own relationships and associations with other models and now it throws me other set of errors which I didn't even have in the first place.
I've also noticed that EF
removes LocalizedName
from the property list and shows it under Navigation
properties list. And lastly, I've checked the OnModelCreating -> modelBuilder.Model.GetEntityTypes()
and noticed that EF is treating it as a new Model
which is kinda weird.
Is there a way I can tell EF
to mark this as a string/json
field instead of EF auto-assuming it's a model?
Any help would be appreciated.
https://stackoverflow.com/questions/65745810/c-sharp-using-entity-framework-core-3-hasconversion-to-convert-a-field-to-json January 16, 2021 at 10:04AM
没有评论:
发表评论