.NET 7 JsonPolymorphic 和 EF Core 7 Json 专栏

mar*_*oss 12 c# entity-framework-core system.text.json .net-7.0 ef-core-7.0

我从 .NET 6 切换到 .NET 7,以利用 .NET 的多态序列化System.Text.Json

在 WebApi 中,序列化和反序列化就像使用这些类型的魅力一样:

[JsonDerivedType(typeof(FileMessageData), typeDiscriminator: nameof(FileMessageData))]
public class FileMessageData : MessageData
{
    public string FileName { get; set; }
}

[JsonPolymorphic]
[JsonDerivedType(typeof(FileMessageData), typeDiscriminator: nameof(FileMessageData))]
public class MessageData
{
    public string InCommon { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

但当谈到 EF Core 7 时,我想使用 Json Column 功能。在一个名为的实体中,我添加了一个以基本类型和此配置命名的MessageEntity属性:DataMessageData

builder.OwnsOne(e => e.Data, ownedNavigationBuilder =>
{
    ownedNavigationBuilder.ToJson();
});
Run Code Online (Sandbox Code Playgroud)

现在我的期望是,当我将一个FileMessageData对象分配给Data属性时,保存的值将是

{
   "$type": "FileMessageData",
   "inCommon": "test",
   "fileName": "hellokitty.png"
}
Run Code Online (Sandbox Code Playgroud)

但不幸的是它始终是一个空对象:

{}
Run Code Online (Sandbox Code Playgroud)

Data当我将实体上的属性类型更改为 时FileMessageData,数据库中的值为:

{
   "inCommon": "test",
   "fileName": "hellokitty.png"
}
Run Code Online (Sandbox Code Playgroud)

无类型鉴别器

作为解决方法,我正在这样做:

var options = new JsonSerializerOptions(JsonSerializerDefaults.General);
builder
    .Property(e => e.Data)
    .HasColumnType("nvarchar")
    .HasMaxLength(4000)
    .HasConversion(
        v => JsonSerializer.Serialize(v, options),
        s => JsonSerializer.Deserialize<MessageData>(s, options)!,
        ValueComparer.CreateDefault(typeof(MessageData), true)
    );
Run Code Online (Sandbox Code Playgroud)

...但这不允许我通过服务器评估查询“InCommon”字段,因为这显然不能转换为查询。

System.InvalidOperationException: 'The LINQ expression 'DbSet<MessageEntity>()
    .Where(m => m.Data.InCommon == "HoHo")' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
Run Code Online (Sandbox Code Playgroud)

如何告诉 EF Core 7 使用多态 JSON 功能序列化/反序列化对象?

小智 0

使用JsonProperty.EFCore可以解决您的问题。它允许您使用多态 json 字段,可编辑为IDictionary<string,object>IList<object>作为实体模型属性。您可以将其安装为 nuget

\n

使用示例:

\n
using JsonProperty.EFCore;\n\n//Create product\nvar product = new Product() { Name = "Car" };\n\n//AddRange\nproduct.Attributes.AddRange(new Dictionary<string, object>() {\n    //You can add values \xe2\x80\x8b\xe2\x80\x8bof different types if the base type is object \n    {"MaxSpeed",300},{ "Engine capacity",3.5}, { "ElectroCar",false }\n});\n\n//Add\nproduct.Attributes.Add("Color", "Red");\n\n//Edit\nproduct.Attributes.Edit(attrs=>{\n    attrs["Color"] = "Blue";\n    return attrs;\n});\n\n//Entity model\npublic class Product\n{\n    public int Id { get; set; }\n    public string Name { get; set; }\n    //Json container property. Same type as JsonDictionary<string,object>\n    public JsonDictionary Attributes{ get; set; } = new();\n}\n
Run Code Online (Sandbox Code Playgroud)\n