如何为List<TModel>实现EF Core自定义ValueComparer与JSON转换器?
解决方案
核心要点
EF Core编译模型要求转换器和比较器必须是可实例化的具体类,不能使用内联匿名实现。针对你的场景,优先用泛型版本的ValueConverter<TModel, TProvider>和ValueComparer<T>,类型安全且复用性强:
TModel:对应实体属性的类型,也就是List<BarModel>TProvider:对应数据库中存储的类型,这里是string(因为你把List序列化为JSON字符串存储)
1. 实现自定义泛型ValueConverter
public class BarListToStringConverter : ValueConverter<List<BarModel>, string> { public BarListToStringConverter() : base( // 模型转数据库:List<BarModel> 序列化JSON model => JsonSerializer.Serialize(model, JsonSerializerOptions.Default), // 数据库转模型:JSON反序列化为List<BarModel> provider => JsonSerializer.Deserialize<List<BarModel>>(provider, JsonSerializerOptions.Default) ?? new List<BarModel>() ) { } }
2. 实现自定义泛型ValueComparer
因为List<T>是引用类型,默认的引用比较不符合需求,需要实现基于内容的比较:
public class BarListValueComparer : ValueComparer<List<BarModel>> { public BarListValueComparer() : base( // 比较两个List的内容是否相等 (list1, list2) => list1.SequenceEqual(list2), // 生成List内容的哈希码 list => list.Aggregate(0, (hash, item) => HashCode.Combine(hash, item.GetHashCode())), // 生成List的快照(用于跟踪变更) list => list.ToList() ) { } }
3. 在DbContext中替换内联配置
在OnModelCreating里,替换原来的内联转换器和比较器,改用自定义类:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<FooModel>() .Property(f => f.BarProperty) .HasConversion(new BarListToStringConverter()) .Metadata.SetValueComparer(new BarListValueComparer()); }
4. 验证优化命令
现在重新执行dotnet ef dbcontext optimize,应该就能正常生成编译模型了。
内容的提问来源于stack exchange,提问作者ˈvɔlə
相关产品推荐
相关产品推荐

