2017-06-06 122 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方法來消除。良好的實現不會產生重複。