npgsql 处理json多态问题

目前.net版本为 9.0, 虽然 EFCore 7.0已经支持json, 但是对多态并不友好,所以目前的json映射依然使用 npgsql提供的方式。

解决问题

  • EFCore 对json多态支持不好
  • npgsql 处理json多态时,默认json顺序找不到metadata
  • 这个metadata指的是C#序列化多态类型时,默认对多态的数据插入$type属性来标记特定的子类型

模型配置

C# 复制代码
public class Marker
{
    public Guid Id { get; set;}
    
    [Column(TypeName = "jsonb")]
    public Meta[] Metas { get; set;}
}

[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] // 元数据的名称为 type
[JsonDerivedType(typeof(MetaImageList), "image-list")]    // 子类型元数据值 "type"="image-list"
[JsonDerivedType(typeof(MetaUrl), "url")]
public class Meta 
{
    public string Name { get; set; }
}

public class MetaUrl : Meta
{
    public string Data { get; set; }
}

public class MetaImageList : Meta
{
    public string[] Data { get; set; }
}

配置DbContext

arduino 复制代码
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
    public DbSet<Marker> Markers => Set<Marker>();
}

依赖注入配置EF Core

C# 复制代码
var services = new ServiceCollection().AddDbContext<AppDbContext>(builder =>
{
    builder.UseNpgsql("connection_string", o =>
    {
        o.ConfigureDataSource(ob =>
        {
            // 支持json
            ob.EnableDynamicJson();
            
            ob.ConfigureJsonOptions(
                new JsonSerializerOptions 
                { 
                    // 小驼峰
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,   
                    
                    // 重要 重要 重要 :允许元数据属性出现在 JSON 对象中的任意位置
                    AllowOutOfOrderMetadataProperties = true
                });
        });
    });
});

使用

C# 复制代码
var sp = services.BuildServiceProvider();
var dbcontext = sp.GetRequiredService<AppDbContext>();
dbcontext.Database.EnsureCreated();

dbcontext.Markers.Add(new Marker
{
    Id = Guid.CreateVersion7(),
    Metas = [new MetaUrl {
        Name = "bilibili",
        Data = "https://www.bilibili.com/"
    },new MetaImageList{
        Name = "图片组",
        Data = ["http://www.example.com/1.jpg"]
    }]
});
dbcontext.SaveChanges();

var markers = dbcontext.Markers.ToList();
Console.WriteLine(JsonSerializer.Serialize(markers, 
    new JsonSerializerOptions { 
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
        WriteIndented = true }));

成果

相关推荐
烛阴3 小时前
bignumber.js深度解析:驾驭任意精度计算的终极武器
前端·javascript·后端
服务端技术栈3 小时前
电商营销系统中的幂等性设计:从抽奖积分发放谈起
后端
你的人类朋友4 小时前
✍️Node.js CMS框架概述:Directus与Strapi详解
javascript·后端·node.js
面朝大海,春不暖,花不开4 小时前
自定义Spring Boot Starter的全面指南
java·spring boot·后端
钡铼技术ARM工业边缘计算机4 小时前
【成本降40%·性能翻倍】RK3588边缘控制器在安防联动系统的升级路径
后端
安木夕5 小时前
C#-Visual Studio宇宙第一IDE使用实践
前端·c#·.net
CryptoPP5 小时前
使用WebSocket实时获取印度股票数据源(无调用次数限制)实战
后端·python·websocket·网络协议·区块链
白宇横流学长5 小时前
基于SpringBoot实现的大创管理系统设计与实现【源码+文档】
java·spring boot·后端
草捏子6 小时前
状态机设计:比if-else优雅100倍的设计
后端
考虑考虑7 小时前
Springboot3.5.x结构化日志新属性
spring boot·后端·spring