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

Mer*_*tez 14 data-conversion dbcontext asp.net-core jsonconverter entity-framework-core-3.1

我在我的 DBContext 中使用了“HasConversion”来定义一个 JSonArray(语言/值)并将它保存为一个文本字段,它的作用就像一个魅力,我在我的解决方案中添加了一个新项目,没有任何改变,但后来我得到了添加有关“设置值比较器”的迁移的新错误。

我的模型是这样的:

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

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})
         );
    });
Run Code Online (Sandbox Code Playgroud)

它运行良好,但在添加新项目后,我在添加迁移时出现黄色错误,并且模型未添加到新数据库中。

Microsoft.EntityFrameworkCore.Model.Validation[10620] 实体类型“品牌”上的属性“名称”是具有值转换器但没有值比较器的集合或枚举类型。设置值比较器以确保正确比较集合/枚举元素。

Sea*_*ull 13

ValueComparer 文档的解释https://docs.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));
Run Code Online (Sandbox Code Playgroud)

然后需要ValueComparer<T>在属性上设置 a以强制 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);
Run Code Online (Sandbox Code Playgroud)

  • 您是说不需要使用 `HasConversion` 吗?我看到你放入了“SetValueComparer”并传递了一个定义的“valueComparer”,但我发现与接收“converter”的“HasConvertion”没有任何连接(OP已匿名传递)。我通常有 `new ValueConverter&lt;T,U&gt;(a =&gt; a.ToU(),b =&gt; b.ToT())`。 (3认同)
  • 您还可以将 valueComparer 作为第三个参数传递给 HasConversion() (3认同)
  • 这是一个单独的调用,因为您无法将其链接到转换。 (2认同)

小智 7

ValueComparer 类文档

为无法与 Equals(Object, Object) 进行比较和/或在拍摄快照时需要深层/结构副本的 CLR 类型指定自定义值快照和比较。例如,如果要检测突变,原始类型的数组将需要两者。

快照是将值的副本创建到快照中的过程,以便以后可以对其进行比较以确定它是否已更改。对于某些类型,例如集合,这需要是集合的深拷贝,而不仅仅是引用的浅拷贝。

您可以在此问题上找到有关如何设置 ValueComparer 的更多信息:

https://github.com/dotnet/efcore/issues/17471