You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 8自定义原始类型集合映射问题求助

EF Core 8嵌套JSON实体中Ulid列表序列化问题解决思路

问题场景

在EF Core 8中定义了嵌套JSON实体,配置如下:

entity.OwnsOne(e => e.EncryptedElements, o =>
{
    o.ToJson();
    o.OwnsMany(x => x.Values, o =>
    {
        o.Property(x => x.Id).IsRequired(); 
        o.PrimitiveCollection(x => x.SearchVector);
        o.PrimitiveCollection(x => x.DataProtectionSetItemIds)
        .Metadata.SetValueComparer(new UlidListComparer());
    });
});

其中SearchVector是ulong列表,DataProtectionSetItemIds是Ulid列表。已通过全局配置将单个Ulid转换为PostgreSQL的bytea类型:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder
        .Properties<Ulid>()
        .HaveConversion<UlidToBytesConverter>();
    // 其他配置...
}

实体中的Id(Ulid类型)序列化后为base64格式,但配置DataProtectionSetItemIds时出现错误:

无法创建类型为'Runtime'的'DbContext'。创建实例时引发异常:“属性'ProtectedValue.DataProtectionSetItemIds'(类型为List)无法映射,因为数据库提供程序不支持该类型。请考虑使用值转换器将属性值转换为数据库支持的类型。或者,使用'[NotMapped]'属性或在'OnModelCreating'中使用'EntityTypeBuilder.Ignore'从模型中排除该属性。”

尝试过将整个集合序列化为单个字符串,但破坏了JSON结构导致无法用PostgreSQL的JSON函数查询;尝试逐个转换Ulid为base64时引发InvalidCastException。

解决方案

直接为DataProtectionSetItemIds配置列表级别的值转换器是最可行的方案,原因是全局单个Ulid转换器针对的是数据库列类型转换,而嵌套JSON场景下需要的是JSON序列化层面的转换,全局转换器无法覆盖这种场景。

1. 实现Ulid列表与base64字符串列表的转换器

public class UlidListToBase64ListConverter : ValueConverter<List<Ulid>, List<string>>
{
    public UlidListToBase64ListConverter()
        : base(
            // 转换为JSON存储的base64字符串列表
            ulidList => ulidList.Select(ulid => Convert.ToBase64String(ulid.ToByteArray())).ToList(),
            // 从JSON的base64字符串列表还原为Ulid列表
            base64List => base64List.Select(base64 => Ulid.FromByteArray(Convert.FromBase64String(base64))).ToList())
    {
    }
}

2. 在实体配置中应用该转换器

修改OnModelCreating中的配置,为DataProtectionSetItemIds添加转换器:

entity.OwnsOne(e => e.EncryptedElements, o =>
{
    o.ToJson();
    o.OwnsMany(x => x.Values, o =>
    {
        o.Property(x => x.Id).IsRequired(); 
        o.PrimitiveCollection(x => x.SearchVector);
        o.PrimitiveCollection(x => x.DataProtectionSetItemIds)
          .HasConversion<UlidListToBase64ListConverter>() // 添加这行
          .Metadata.SetValueComparer(new UlidListComparer());
    });
});

关键说明

  • 这个转换器会直接将List<Ulid>序列化为JSON数组形式的base64字符串列表,既满足序列化格式要求,又能保留JSON结构,让PostgreSQL的JSON函数正常查询。
  • 避免了将整个集合序列化为单个字符串的问题,同时解决了逐个转换时的类型异常——直接处理列表级别的转换,绕过了EF Core对单个Ulid在JSON场景下的类型映射冲突。

内容的提问来源于stack exchange,提问作者ZorgoZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 05:12:43