递归linq结果返回重复

时间:2017-06-06 19:17:10

标签: c# asp.net-mvc entity-framework linq linq-to-entities

这个问题是基于我上周问过的问题:Recursive linq to get infinite children。那篇文章给出的答案产生了我所需要的东西;基于父级的不同位置及其子级列表。我们需要使用我们自己的Locations模型,所以我们创建了一个,从那时起,我一直在获得重复的结果。我们的模型非常基础:

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

如果将它与EF创建的实体进行比较,我只会删除所有不需要/使用的字段(参见上面的链接)。所以我修改了我的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);
}

当我在Visual Studio或LinqPad中运行它时,我现在得到了重复项。这是产生重复项的原始代码:

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;
}

为什么当我使用自己的模型而不是EF生成的模型时,它会产生重复?是否与EF模型具有的自动生成字段有关,而我的不是?

1 个答案:

答案 0 :(得分:3)

  

为什么当我使用自己的模型而不是EF中生成的模型时会产生重复?

因为您使用的是Enumerable.Union方法,默认情况下使用引用相等。 EF DbContext更改跟踪器使用相同的PK在内部(跟踪)已加载的实体对象实例(即使您通过单独的数据库查询检索它们),因此引用相等也可以。对于查询new LocationModel运算符创建的select实例,无法说明。

解决此问题的一种方法是在GetHashCode课程中实施EqualsLocationModel。但总的来说,我不喜欢递归子检索的实现和Union的使用 - 必须有更好的方法,但这超出了这个问题的范围(但对于链接)。

邪恶的根源是以下条件

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

选择项目及其子项,导致结果集中的重复项,然后应该由Union方法消除。好的实现根本不会产生重复。