实体框架AsNoTracking打破呼叫鲜明 [英] Entity Framework AsNoTracking breaks call to Distinct

查看:125
本文介绍了实体框架AsNoTracking打破呼叫鲜明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从一个页面上的产品先前加载列表装入不同颜色的列表。因此,要拉我做的产品有:

  VAR产品=产品
.INCLUDE(P =指p .ProductColor)
.ToList();



然后我做的产品他们一些处理我想要得到所有不同颜色的列表在产品上,所以我这样做:

  VAR颜色=产品
。选择(p =指p .ProductColor)
.Distinct();

和这个伟大的工程,但是如果我添加了一个调用 .AsNoTracking( )原来的产品叫,我现在得到我在产品列表中的每个条目的颜色列表中的条目。



为什么会出现在这两个的区别?有没有一种方法,以保持实体框架从跟踪的对象(它们被用于只读),并获得所需的行为?



这是加入后我的查询调用 AsNoTracking()

  VAR产品=产品
.AsNoTracking()
.INCLUDE(p => p.ProductColor)
.ToList();


解决方案

AsNoTracking 休息鲜明,因为 AsNoTracking 休息标识映射。由于装载了 AsNoTracking()实体将不会被附加到上下文缓存EF物化的新实体的每一行从查询返回,而启用跟踪时,它会检查是否有实体确实存在的背景下,如果是,它不会创建一个新的对象,只是使用附加的对象实例,而不是相同的密钥值。



例如对于如果你有2个产品无一不是绿色:




  • 没有 AsNoTracking()您的查询一定会实现3个对象:2 产品对象和1 ProductColor 对象(绿色)。产品1有(在 ProductColor 属性)绿色的参考和产品2有一个参考的对同一个对象实例的绿色,即



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


  • 通过 AsNoTracking()您的查询一定会实现4个对象:2产品对象和2色的对象(包括代表绿色,并有相同的键的值)。产品1有(在 ProductColor 属性)绿色的参考和产品2有绿色的引用,但这是的另一个对象实例的,即

      object.ReferenceEquals(product1.ProductColor,product2.ProductColor)==虚假




现在,如果你调用鲜明的()上在内存集合(LINQ到对象)为默认的比较鲜明的()无参数的比较对象引用身份。所以,如果你1只得到1绿色的对象,但如果2,你会得到2绿色物体。



要得到期望的结果你已经运行查询后与 AsNoTracking()您需要通过实体键的比较。您可以使用鲜明这需要一个的IEqualityComparer 的第二个重载为参数。其实施的一个例子这里是,你会使用 ProductColor 来比较两个对象



或者 - 这似乎比繁琐的IEqualityComparer 实施 - 你重写鲜明的()在 GROUPBY (用 ProductColor 键属性为分组键):

  VAR颜色=产品
。选择( p => p.ProductColor)
.GroupBy(PC => pc.ProductColorId)
。选择(G => g.First());



第一()基本上意味着你扔所有重复路程,只保留每个键值的第一个对象实例。


I am trying to load a list of distinct colors from previously loaded list of products on a page. So to pull in the products I do this:

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

Then I do some processing on the products them I want to get a list of all of the distinct colors used by the products, so I do this:

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

And this works great, however if I add a call to .AsNoTracking() to the original products call, I now get an entry in my color list for each entry in the product list.

Why is there a difference in these two? Is there a way to keep Entity Framework from tracking the objects (they're being used for read only) and to get the desired behavior?

Here is my query after adding the call to AsNoTracking()

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

解决方案

AsNoTracking "breaks" Distinct because AsNoTracking "breaks" identity mapping. Since entities loaded with AsNoTracking() won't get attached to the context cache EF materializes new entities for every row returned from the query whereas when tracking is enabled it would check if an entity with the same key value does already exist in the context and if yes, it wouldn't create a new object and just use the attached object instance instead.

For example, if you have 2 products and both are Green:

  • Without AsNoTracking() your query will materialize 3 objects: 2 Product objects and 1 ProductColor object (Green). Product 1 has a reference to Green (in ProductColor property) and Product 2 has a reference to the same object instance Green, i.e.

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

  • With AsNoTracking() your query will materialize 4 objects: 2 product objects and 2 color objects (both represent Green and have the same key value). Product 1 has a reference to Green (in ProductColor property) and Product 2 has a reference to Green but this is another object instance, i.e.

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

Now, if you call Distinct() on a collection in memory (LINQ-to-Objects) the default comparison for Distinct() without parameter is comparing object reference identities. So, in case 1 you get only 1 Green object, but in case 2 you'll get 2 Green objects.

To get the desired result after you have run the query with AsNoTracking() you need a comparison by the entity key. You can either use the second overload of Distinct which takes an IEqualityComparer as parameter. An example for its implementation is here and you would use the key property of ProductColor to compare two objects.

Or - which seems easier to me than the tedious IEqualityComparer implementation - you rewrite the Distinct() using a GroupBy (with the ProductColor key property as the grouping key):

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

The First() basically means that you are throwing all duplicates away and just keep the first object instance per key value.

这篇关于实体框架AsNoTracking打破呼叫鲜明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆