2021年1月15日星期五

C# - Using Entity Framework Core 3 HasConversion to convert a field to JSON in .Net Core 3.1

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

没有评论:

发表评论