2014-01-25 58 views
5
我無法得到這個LINQ到哪裏返回任何結果

,我有幾類這樣的:LINQ,第三個嵌套的孩子的財產價值等於什麼?

public class RestaurantMenu 
{ 
    public List<MenuItem> MenuItems { get; set; } 
} 

public class MenuItem 
{ 
    public decimal Price { get; set; } 
    public List<FoodItem> FoodItems { get; set; } 
} 

public class FoodItem 
{ 
    public string Label { get; set; } 
} 

鑑於RestaurantMenu列表,我試圖返回任何匹配的結果,其中餐廳菜單的菜單商品的食品商品標籤與列表中的所有字符串匹配。基本上,你輸入你想吃的食物,它應該返回任何餐館,他們有你想吃的所有東西。它應該支持多個字符串,但我甚至無法匹配一個字符串。

所以假設如下:

List<RestaurantMenu> allRestaurantMenus = /blah; 
List<string> labelOfFoodsDesired = /blah; 

我試圖通過鏈接做在那裏表情就像這樣:

IQueryable<RestaurantMenu> query = allRestaurantMenus.AsQueryable(); 

     foreach (string foodItem in labelOfFoodItemsDesired) 
     { 
      query = query.Where(x => x.MenuItems.Any(y => y.FoodItems.Select(z => z.Label).Contains(foodItem))); 
     } 

     List<RestaurantMenu> matchingRestaurantMenus = query.ToList(); 

但它總是不返回任何結果,即使通過調試我肯定有一場比賽。我怎麼寫這個查詢?

+0

我認爲你的鏈接調用有什麼問題是你正在重新分配查詢變量。因此,您的查詢具有所有的菜單菜單都會設置爲空或空列表。 – Miguel

+0

如果我理解正確,那麼不是這樣。由於可查詢對象的延遲執行,我可以像上面那樣構造查詢,並且在我調用列表之前它不會實際執行。 (x => id == 2).Where(x => x.Id == 3).Where(x => x.Id == 4)將與查詢無異。它在執行前將它們組合成query.Where(x => x.Id == 2 && x.Id == 3 && x.Id == 4)的單個查詢。不是那樣會返回任何結果,因爲這是不可能的,但僅僅是一個例子。 – SventoryMang

回答

3
allRestaurantMenus.Where(m => 
    m.MenuItems.Any(mi => 
     !labelOfFoodsDesired.Except(mi.FoodItems.Select(fi => fi.Label)).Any())) 

它是如何工作:我們正在篩選具有與您傳遞的所有標籤至少一個菜單項的菜單。隨着Enumerable.Except

!labelOfFoodsDesired.Except(mi.FoodItems.Select(fi => fi.Label)).Any() 

我們生產所需的設置標籤和食品項的所有標籤之間的差異。如果食品標籤中存在所有需要的標籤,則設置爲空。

更新:如果您應該檢查所有菜單項(不是單一的一個),那麼查詢將看起來像

allRestaurantMenus.Where(m => 
    !labelOfFoodsDesired.Except(
     m.MenuItems.SelectMany(mi => mi.FoodItems.Select(fi => fi.Label))).Any()) 

它是如何工作的:方法同上,但你應該檢查所有的所有標籤菜單項。這是通過Enumerable.SelectMany完成的,它將菜單項的集合平整爲所有標籤的集合。然後,如上所述,您可以在所需的標籤和所有菜單項的所有標籤之間建立設置差異。如果設置爲空,則菜單滿足您的條件。

TEST:鑑於以下菜單

List<RestaurantMenu> allRestaurantMenus = new List<RestaurantMenu> { 
    new RestaurantMenu { 
      MenuItems = new List<MenuItem> { 
       new MenuItem { 
        FoodItems = new List<FoodItem> { 
         new FoodItem { Label = "Chocolate" }, 
         new FoodItem { Label = "Water" } 
        } 
       }, 
       new MenuItem { 
        FoodItems = new List<FoodItem> { 
         new FoodItem { Label = "Egg" }, 
         new FoodItem { Label = "Ketchup" } 
        } 
       } 
      } 
    }, 
    new RestaurantMenu { 
     MenuItems = new List<MenuItem> { 
       new MenuItem { 
        FoodItems = new List<FoodItem> { 
         new FoodItem { Label = "Water" } 
        } 
       }, 
       new MenuItem { 
        FoodItems = new List<FoodItem> { 
         new FoodItem { Label = "Banana" }, 
         new FoodItem { Label = "Peach" } 
        } 
       } 
      } 
     } 
}; 

而繼期望標籤

List<string> labelOfFoodsDesired = new List<string> 
{ 
    "Water", "Banana" 
}; 

查詢上面會壓扁菜單所有標籤的序列:

{ "Chocolate", "Water", "Egg", "Ketchup" } 
{ "Water", "Banana", "Peach" } 

然後它將建設置期望的標籤和平展結果之間的差異:

{ "Banana" } 
{ } 

因此第二個結果是空的(菜單中存在所有需要的標籤),只有第二個菜單匹配。

+1

這不完全是我所需要的,我很抱歉,如果我解釋得不好。菜單需要有所有需要的食物,但它不一定是單個菜單項目,它可以在單個菜單項目中,或者它可以在多個菜單項目上,只要它們全部在一個菜單項目上餐廳。 – SventoryMang

+1

@DOTang沒問題,更新了查詢。在這種情況下,您應該將所有菜單項平鋪到標籤集合中,並檢查平鋪集合中是否存在所有所需標籤。 –

+0

最後一個仍然返回零結果。我正在更新我的問題以包含示例數據。 – SventoryMang

0

我認爲這樣的事情會起作用。我相信你可以刪除foreach,這是一個單一的linq查詢。

foreach (var restaurant in allRestaurantMenus) 
{ 
    var restaurantFoodItems = restaurant.MenuItems.SelectMany(m => m.FoodItems); 
    bool hasAllFoods = labelOfFoodsDesired.All(lf => restaurantFoodItems.Contains(lf)); 

    if (hasAllFoods) 
     yield return restaurant; 
} 
0

你可以使用的WhereExcept這個組合 - Any

var allMatches = allRestaurantMenus 
    .Where(rm => !labelOfFoodsDesired 
     .Except(rm.MenuItems.SelectMany(f => f.FoodItems.Select(fi => fi.Label))) 
     .Any()); 

labelOfFoodsDesired.Except(allmenu-food-item-labels).Any()回報true如果一個或多個期望的標籤都沒有。該!扭轉的情況,所以它檢查所有食物可用。由於Except在內部使用了一個集合,所以效率很高。

0
allRestaurantMenus.Where(x => labelOfFoodsDesired.All(b => x.MenuItems.SelectMany(y => y.FoodItems.Select(a => a.Label)).Contains(b))); 

通過將所有食物放入清單中,然後對所有需要的食物進行檢查,檢查它們是否在列表中。