我对实体框架的 JSON 列支持感到很兴奋。但是,我在配置我的实体以使用它时遇到问题。这是我的实体,为清楚起见进行了简化:
public class Bill : EntityBase
{
public DateTimeOffset BillDate { get; set; } = DateTimeOffset.Now;
public DateTimeOffset? DeliveryDate { get; set; }
public IList<string> OrderNumbers { get; set; } = new List<string>();
public IList<string> CustomerOrderNumbers { get; set; } = new List<string>();
我使用
IEntityTypeConfiguration<T>
来配置我的实体,因为我发现我在如何设置表方面获得了很多粒度。这是相应的配置:
public class BillConfiguration : IEntityTypeConfiguration<Bill>
{
public void Configure(EntityTypeBuilder<Bill> builder)
{
// Primary Key
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasColumnOrder(0);
// (snipping audit and version columns)
// Property settings
builder.Property(x => x.BillDate)
.HasColumnOrder(6);
builder.Property(x => x.DeliveryDate)
.HasColumnOrder(7);
builder.Property(x => x.OrderNumbers)
.HasColumnOrder(8);
builder.Property(x => x.CustomerOrderNumbers)
.HasColumnOrder(9);
但是,在创建初始迁移时,它会抛出以下错误:
The property 'Bill.CustomerOrderNumbers' could not be mapped because it is of type 'IList<string>', which is not a supported primitive type or a valid entity type. Either explicitly map this property, or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
这个错误是有道理的,但我不确定“支持”来自哪里。我做了一个转换器:
public class StringListValueConverter : ValueConverter<IList<string>, string>
{
public StringListValueConverter()
: base(
value => JsonSerializer.Serialize(value, JsonSerializerOptions.Default),
dbValue => JsonSerializer.Deserialize<IList<string>>(dbValue, JsonSerializerOptions.Default) ?? new List<string>()
)
{
}
}
然后我可以根据
这篇博文在列上使用
.HasConversion<StringListValueConverter>()
。
我不明白 EF 的新“功能”在哪里。我不能一直这样做吗?有没有更简单的方法来做到这一点而不需要手动转换?
我相信您可能错过了转换电话。这是 .NET 6 中的一个示例;请放心使用。
上下文文件:
// builder
model.Entity<Bill>()
.Property(t => t. OrderNumbers)
.HasColumnType("nvarchar(max)")
.HasJsonConversion();
扩展方法:
public static PropertyBuilder<T> HasJsonConversion<T>(this PropertyBuilder<T> propertyBuilder)
{
var converter = new ValueConverter<T, string>(
v => JSerialize(v),
v => JDeserialize<T>(v));
var comparer = new ValueComparer<T>(
(l, r) => JSerialize(l) == JSerialize(r),
v => v == null ? 0 : JSerialize(v).GetHashCode(),
v => JDeserialize<T>(JSerialize(v)));
propertyBuilder.HasConversion(converter);
propertyBuilder.Metadata.SetValueConverter(converter);
propertyBuilder.Metadata.SetValueComparer(comparer);
return propertyBuilder;
}
注意:更改 json 转换器。
我不明白 EF 的新“功能”在哪里
这是可以理解的,因为此时官方文档尚未更新,并且“新功能”仅在 EF Core 7 的“新增功能”部分中解释 - JSON Columns。
该功能应该仅针对拥有的实体类型(OwnsOne
/
OwnsMany
)使用相应构建器的
ToJson()
流利API激活。但是,文档说
注意这仅仅意味着您不能将它用于您的尚不支持将原始类型集合映射到 JSON。上面的文档使用值转换器将集合转换为逗号分隔的字符串。投票给
Json:添加对原始类型集合的支持(如果您对此感兴趣)。
string
列表,而应该求助于旧的超值转换器。至少在 EF7 中是这样。根据链接的 GitHub 问题,它已在即将推出的 EF8 中实现。怎么办 - 我现在不知道,EF8 还没有发布,我有一个强烈的政策,不尝试/测试预览软件。