目前.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 }));