2012-01-17 2 views
8

Я хотел бы иметь возможность запрашивать родительские объекты и фильтровать содержимое дочерней коллекции.LINQ - фильтрация дочерней коллекции

Например, у меня есть коллекция OrderHeaders. Я хочу запросить эту коллекцию с помощью LINQ, чтобы вернуть все OrderHeaders, но я хочу, чтобы некоторые связанные строки OrderDetail были включены.

Я предпочитаю найти решение, где я могу сделать все это в одном заявлении LINQ.

Данное консольное приложение демонстрирует это.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace LINQ 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<OrderHeader> orders = GetOrderHeaders(); 

      var filteredOrders = from p in orders 
           where p.Detail.Where(e => e.StockCode == "STK2").Count() > 0 
           select p; 

      foreach (var order in filteredOrders) 
      { 
       Console.WriteLine("Account {0} ", order.AccountCode); 

       foreach (var detail in order.Detail) 
       { 
        Console.WriteLine("StockCode {0}, Quantity {1}", detail.StockCode, detail.Quantity); 
       } 

       Console.WriteLine(); 
      } 

      // The above will return the following: 
      // Account CUST1 
      // StockCode STK1, Quantity 1 
      // StockCode STK2, Quantity 2 
      // 
      // Account CUST2 
      // StockCode STK2, Quantity 1 
      // StockCode STK4, Quantity 2 

      // How can I get the following? 
      // Account CUST1 
      // StockCode STK2, Quantity 2 
      // 
      // Account CUST2 
      // StockCode STK2, Quantity 1 

      Console.ReadLine(); 
     } 

     public static List<OrderHeader> GetOrderHeaders() 
     { 
      List<OrderHeader> orders = new List<OrderHeader>(); 

      OrderHeader header = 
       new OrderHeader { 
        AccountCode = "CUST1", 
        Detail = new List<OrderDetail>()}; 
      header.Detail.Add(
       new OrderDetail { StockCode = "STK1", Quantity = 1 }); 
      header.Detail.Add(
       new OrderDetail { StockCode = "STK2", Quantity = 2 }); 
      orders.Add(header); 

      header = 
       new OrderHeader 
       { 
        AccountCode = "CUST2", 
        Detail = new List<OrderDetail>() 
       }; 
      header.Detail.Add(
       new OrderDetail { StockCode = "STK2", Quantity = 1 }); 
      header.Detail.Add(
       new OrderDetail { StockCode = "STK4", Quantity = 2 }); 
      orders.Add(header); 

      return orders; 
     } 
    } 

    public class OrderHeader 
    { 
     public string AccountCode { get; set; } 
     public List<OrderDetail> Detail {get; set;} 
    } 

    public class OrderDetail 
    { 
     public string StockCode { get; set; } 
     public int Quantity { get; set; } 
    } 

} 

Большое спасибо за любые предложения.

Пол

+1

Почему одержимость одной инструкции LINQ? –

+0

Я должен дать больше информации на этот вопрос. На самом деле я использую LINQ для Entity Framework, где я генерирую инструкцию LINQ с помощью Dynamic Expression API (в результате чего пользователь создает критерии поиска с пользовательским интерфейсом). Из-за этого я бы предпочел сделать это в одном заявлении LINQ. – P2l

ответ

16

Попробуйте следующее:

var filtered = orders 
    .Where(o => o.Detail.Any(d => d.StockCode == "STK2")) 
    .Select(o => new { Order = o, Details = o.Detail.Where(d => d.StockCode == "STK2") }); 

Что то полезное, так как:

foreach (var entity in filtered) 
{ 
    Console.WriteLine("Account {0} ", entity.Order.AccountCode); 
    foreach (var detail in entity.Details) 
    { 
     Console.WriteLine("StockCode {0}, Quantity {1}", detail.StockCode, detail.Quantity); 
    } 
    Console.WriteLine(); 
} 
+1

Не переменная в Any должна быть чем-то иным, чем «o», чтобы не изменять значение «o» в родительском? –

+0

@ ScottA.Lawrence Да, вы правы - мой фрагмент кода не будет компилироваться. Ответ обновлен, спасибо. –

+0

@ rich-okelly, пожалуйста, рада помочь. –

Смежные вопросы