在ASP.NET Core 3.1中设置值比较器

23

我在我的 DBContext 中使用了 "HasConversion" 来定义一个 JSonArray(Language/Value),并将其保存为 Text 字段已经有一段时间了,它一直很好用。我添加了一个新项目到我的解决方案中,除此之外什么都没改变,但是当我添加 migration 时出现了一个关于 "设置值比较器" 的新错误。

我的模型如下:

    public class Brand
    {
        public int Id { get; set; }
        public new IList<LangValue> Name { get; set; } = new List<LangValue>();
    }

DBContext 就像这样:

    modelBuilder.Entity<Brand>(t =>
    {

        t.Property(p => p.Name).HasConversion(
            v => JsonConvert.SerializeObject(v, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Include}),
            v => JsonConvert.DeserializeObject<IList<LangValue>>(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Include})
         );
    });

它之前一直很完美,但是在添加了一个新项目后,我在添加迁移时遇到了黄色错误并且模型没有添加到新的数据库中。

Microsoft.EntityFrameworkCore.Model.Validation[10620] 实体类型 'Brand' 上的属性 'Name' 是具有值转换器但没有值比较器的集合或枚举类型。设置一个值比较器以确保正确比较集合/枚举元素。

2个回答

28

ValueComparer文档中的解释:https://learn.microsoft.com/en-us/ef/core/modeling/value-comparers#mutable-classes

列表属性上的典型值转换可能会将列表转换为JSON格式:

modelBuilder
    .Entity<EntityType>()
    .Property(e => e.MyProperty)
    .HasConversion(
        v => JsonSerializer.Serialize(v, null),
        v => JsonSerializer.Deserialize<List<int>>(v, null));

因此,这需要在属性上设置ValueComparer<T>,以强制EF Core使用正确的比较进行转换:

这要求在属性上设置ValueComparer<T>,以确保EF Core在执行转换时使用正确的比较。

var valueComparer = new ValueComparer<List<int>>(
    (c1, c2) => c1.SequenceEqual(c2),
    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
    c => c.ToList());

modelBuilder
    .Entity<EntityType>()
    .Property(e => e.MyProperty)
    .Metadata
    .SetValueComparer(valueComparer);

3
你的意思是说不需要使用HasConversion吗?我看到你使用了SetValueComparer并传递了一个定义好的valueComparer,但我没有看到它与HasConvertion接收的转换器有任何关系(OP将其匿名传递)。通常我会使用类似于new ValueConverter<T,U>(a => a.ToU(),b => b.ToT())的东西。 - Konrad Viltersten
2
它是一个单独的调用,无法将其链接到转换。 - Christian O.
2
你还可以将valueComparer作为HasConversion()的第三个参数传递 - Thomas

7
ValueComparer类文档中可以看到:
指定CLR类型的自定义值快照和比较,这些类型不能使用Equals(Object,Object)进行比较和/或在进行快照时需要进行深度/结构复制。例如,原始类型数组将需要两者都进行,如果要检测到突变。
快照是将值创建为快照的过程,以便稍后可以将其与先前的值进行比较,从而确定它是否已更改。对于某些类型,例如集合,这需要对集合进行深层复制,而不仅仅是引用的浅复制。
您可以在此问题上找到有关如何设置ValueComparer的更多信息:https://github.com/dotnet/efcore/issues/17471

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接