gpt4 book ai didi

c# - Entity Framework AsNoTracking 中断对 Distinct 的调用

转载 作者:太空狗 更新时间:2023-10-29 18:09:23 25 4
gpt4 key购买 nike

我正在尝试从页面上先前加载的产品列表中加载不同颜色的列表。因此,为了引入产品,我这样做:

var products = Products
.Include(p => p.ProductColor)
.ToList();

然后我对产品进行一些处理,我想获得产品使用的所有不同颜色的列表,所以我这样做:

var colors = products   
.Select(p => p.ProductColor)
.Distinct();

这很好用,但是如果我将对 .AsNoTracking() 的调用添加到原始产品调用中,我现在会在产品列表中的每个条目的颜色列表中得到一个条目。

为什么这两者有区别?有没有办法阻止 Entity Framework 跟踪对象(它们被用于只读)并获得所需的行为?

这是我在添加对 AsNoTracking() 的调用后的查询

var products = Products
.AsNoTracking()
.Include(p => p.ProductColor)
.ToList();

最佳答案

AsNoTracking“打破”Distinct 因为AsNoTracking“打破”身份映射。由于使用 AsNoTracking() 加载的实体不会附加到上下文缓存,因此 EF 会为从查询返回的每一行具体化新实体,而当启用跟踪时,它会检查实体是否具有相同的键值确实已经存在于上下文中,如果是,它不会创建新对象,而只是使用附加的对象实例。

例如,如果您有 2 种产品并且都是绿色的:

  • 如果没有 AsNoTracking(),您的查询将具体化 3 个对象:2 个 Product 对象和 1 个 ProductColor 对象(绿色)。产品 1 引用了绿色(在 ProductColor 属性中),产品 2 引用了同一对象实例绿色,即

    object.ReferenceEquals(product1.ProductColor, product2.ProductColor) == true
  • 使用 AsNoTracking(),您的查询将具体化 4 个对象:2 个产品对象和 2 个颜色对象(均代表绿色并具有相同的键值)。产品 1 引用了绿色(在 ProductColor 属性中),产品 2 引用了绿色,但这是另一个对象实例,即

    object.ReferenceEquals(product1.ProductColor, product2.ProductColor) == false

现在,如果您在内存中的集合上调用 Distinct()(LINQ-to-Objects),不带参数的 Distinct() 的默认比较是比较对象引用身份。因此,在情况 1 中你只会得到 1 个绿色对象,但在情况 2 中你会得到 2 个绿色对象。

要在使用 AsNoTracking() 运行查询后获得所需结果,您需要通过实体键进行比较。您可以使用 Distinct 的第二个重载,它以 IEqualityComparer 作为参数。其实现的一个例子是 here并且您将使用 ProductColor 的关键属性来比较两个对象。

或者 - 这对我来说似乎比乏味的 IEqualityComparer 实现更容易 - 你使用 GroupBy 重写 Distinct()(使用 ProductColor 键属性作为分组键):

var colors = products   
.Select(p => p.ProductColor)
.GroupBy(pc => pc.ProductColorId)
.Select(g => g.First());

First() 基本上意味着您将丢弃所有重复项,只保留每个键值的第一个对象实例。

关于c# - Entity Framework AsNoTracking 中断对 Distinct 的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17097736/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com