简体   繁体   English

递归linq结果返回重复项

[英]Recursive linq results returning duplicates

This question builds off of one I asked last week: Recursive linq to get infinite children . 这个问题基于我上周提出的一个问题: 递归linq来获得无限个孩子 The answer given in that post produced what I needed; 那篇文章给出的答案满足了我的需求。 a distinct list of Locations and their children based on a parent. 基于父项的位置及其子项的明确列表。 We needed to use our own model for Locations, so we created one, and since then, I've been getting duplicate results. 我们需要对位置使用自己的模型,因此我们创建了一个模型,从那时起,我一直得到重复的结果。 Our model is very basic: 我们的模型非常基础:

class LocationModel
{
    public int LocationID { get; set; }
    public int ParentLocationID { get; set; }
    public string LocationName { get; set;}
}

If you compare it to the entity created by EF, I just cut out all the fields we don't need/use (see link above). 如果您将其与EF创建的实体进行比较,则只删除了我们不需要/不使用的所有字段(请参见上面的链接)。 So I modified my linq statements to use this new model instead: 因此,我修改了linq语句以使用此新模型:

DBEntities db = new DBEntities();

public IEnumerable<LocationModel> GetAllChildLocations(int parentId)
{
    var locations = (from l in db.Locations
                        where l.ParentLocationID == parentId ||
                        l.LocationID == parentId
                        select new LocationModel()
                        {
                            LocationID = l.LocationID,
                            ParentLocationID = l.ParentLocationID,
                            LocationName = l.LocationName
                        }).ToList();

    var children = locations.AsEnumerable()
                            .Union(db.Locations.AsEnumerable()
                            .Where(x => x.ParentLocationID == parentId)
                            .SelectMany(y => GetAllChildLocations(y.LocationID)))
                            .ToList();
    return children.OrderBy(l => l.LocationName);
}

When I run it, either in Visual Studio or in LinqPad, I now get duplicates. 在Visual Studio或LinqPad中运行它时,我现在得到了重复项。 Here's the original code that does not produce duplicates: 这里是原来的代码产生重复:

public IEnumerable<Location> GetAllChildLocations(int parentId)
{
    var locations = (from l in db.Locations
                        where l.ParentLocationID == parentId ||
                        l.LocationID == parentId
                        select l).ToList();

    var child = locations.AsEnumerable()
                        .Union(db.Locations.AsEnumerable()
                        .Where(x => x.ParentLocationID == parentId)
                        .SelectMany(y => GetAllChildLocations(y.LocationID)))
                        .ToList();
    return child;
}

Why is it producing duplicates when I use my own model vs. the generated one from EF? 为什么使用我自己的模型而不是EF生成的模型会产生重复? Does it have to do with the auto-generating fields that the EF model has and mine doesn't? 它是否与EF模型具有的自动生成字段有关,而我的没有?

Why is it producing duplicates when I use my own model vs. the generated one from EF? 为什么使用我自己的模型而不是EF生成的模型会产生重复?

Because you are using Enumerable.Union method which by default uses reference equality. 因为您使用的是Enumerable.Union方法,默​​认情况下使用引用相等。 EF DbContext change tracker keeps internally (tracks) the already loaded entity object instances with the same PK (even if you retrieve them via separate database queries), hence the reference equality works. EF DbContext更改跟踪器在内部(跟踪)具有相同PK的已加载实体对象实例(即使您通过单独的数据库查询检索它们也是如此),因此引用相等性起作用。 Which cannot be said for the new LocationModel instances created by the query select operators. 对于查询select运算符创建的new LocationModel实例,不能说哪个。

One way to resolve it is to implement GetHashCode and Equals in your LocationModel class. 解决它的一种方法是在LocationModel类中实现GetHashCodeEquals But in general I don't like the implementation of the recursive children retrieval and the usage of Union - there must be a better way, but this is outside the scope of this question (but for the linked). 但总的来说,我不喜欢递归子级检索的实现和Union的使用-必须有更好的方法,但这不在此问题的范围内(但对于链接而言)。

The root of the evil for me is the following condition 对我来说,邪恶的根源在于以下条件

where l.ParentLocationID == parentId || l.LocationID == parentId

which selects both the item and its children, leading to duplicates in the result set, which then are supposed to be eliminated by the Union method. 它同时选择了项目及其子项,从而导致结果集中出现重复项,然后应通过Union方法消除这些重复项。 The good implementation will not generate duplicates at all. 好的实现根本不会生成重复项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM