2017-06-06 123 views
0

这个问题是建立在我上周提问的一个问题上的:Recursive linq to get infinite children。在这篇文章中给出的答案产生了我需要的东西;基于父母的地点及其子女的明确列表。我们需要使用我们自己的地点模型,所以我们创建了一个模型,从那以后,我得到了重复的结果。我们的模型是非常基本的:递归linq结果返回重复项

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模型具有的自动生成字段不兼容?

回答

3

为什么当我使用我自己的模型与EF生成的模型产生重复?

因为你正在使用它默认使用参考平等Enumerable.Union方法。 EF DbContext更改跟踪器内部保存(跟踪)已加载的对象实例具有相同的PK(即使通过单独的数据库查询检索它们),因此引用相等。对于由查询select运算符创建的new LocationModel实例,这不能说。

解决它的一种方法是在您的LocationModel类中实现GetHashCodeEquals。但总的来说,我不喜欢递归子检索的实现和Union的使用 - 必须有更好的方法,但这不在这个问题的范围内(但对于链接)。

恶为我的根是下述条件

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

,其选择两个项及其子,导致在结果集中的重复,然后都应该由Union方法来消除。良好的实现不会产生重复。