C#-在.Net Core 3.1中使用Entity Framework Core 3 HasConversion将字段转换为JSON [英] 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
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);
}
然后创建了一个数据注释属性,以将模型中的字段标记为"Json"
Then created a data annotation attribute to mark my fields in my model as "Json"
public class HasJsonConversionAttribute : Attribute {}
这是我的扩展方法,用于将Json转换为对象再转换回Json
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; }
}
这是我想与JSON相互转换的类:
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; }
}
现在这是我面临的问题,它继续将 LocalizedName
对象检测为另一个没有 Key
的 model
抛出一个错误,告诉我添加 Key/PK
,即使未将其标记为模型.
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.
现在,如果我从 User->执行此操作,Configure()
它将起作用,但会向我显示其他问题,例如该模型失去与其他模型的关系和关联,而现在却抛出了我本来没有的其他错误集
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.
我还注意到, EF
从属性列表中删除了 LocalizedName
,并将其显示在 Navigation
属性列表下.最后,我检查了 OnModelCreating->modelBuilder.Model.GetEntityTypes()
,并注意到EF将其视为一种新的 Model
,这有点奇怪.
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.
有没有一种方法可以告诉 EF
将其标记为 string/json
字段,而不是EF自动假定它是模型?
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?
任何帮助将不胜感激.
推荐答案
所以我最终使用了
So I ended up using this NuGet package
from https://github.com/Innofactor/EfCoreJsonValueConverter
然后在我的 DbContext.cs
中:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<LocalizedName>(); //<--- Ignore this model from being added by convention
modelBuilder.AddJsonFields(); //<--- Auto add all json fields in all models
}
然后在我的用户模型
中:
public class User : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder) {}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Username { get; set; }
[JsonField] //<------ Add this attribute
public List<LocalizedName> Values { get; set; }
}
现在它可以正常工作了.
Now it works as expected.
这篇关于C#-在.Net Core 3.1中使用Entity Framework Core 3 HasConversion将字段转换为JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!