EF Core 8自定义原始类型集合映射问题求助
问题场景
在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

