2012-01-17 27 views
8

Chciałbym móc zapytać o nadrzędne jednostki i filtrować zawartość kolekcji dziecięcej.LINQ - filtr kolekcji dzieci

Na przykład mam kolekcję OrderHeaders. Chcę zapytać o tę kolekcję za pomocą LINQ, aby zwrócić wszystkie klasy OrderHeaders, ale chcę, aby tylko niektóre z powiązanych wierszy OrderDetail zostały uwzględnione.

Najlepiej szukam rozwiązania, w którym mogę to wszystko zrobić w pojedynczym oświadczeniu LINQ.

Ta aplikacja konsolowa demonstruje to.

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

} 

Bardzo dziękuję z góry za wszelkie sugestie.

Paul

+1

Dlaczego obsesja pojedynczej instrukcji LINQ? –

+0

Powinienem podać więcej informacji na to pytanie. W rzeczywistości używam LINQ do Entity Framework, w którym generuję instrukcję LINQ za pomocą interfejsu API Dynamic Expression (w wyniku budowania przez użytkownika kryteriów wyszukiwania za pomocą interfejsu użytkownika). Z tego powodu wolałbym to zrobić na jednym wyciągu LINQ. – P2l

Odpowiedz

16

Spróbuj wykonać następujące czynności:

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

który następnie jest użyteczny tak:

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

Czy zmienna w Any nie musi być czymś innym niż "o", aby nie zmienić znaczenia "o" w rodzicu? –

+0

@ ScottA.Lawrence Tak, masz rację - mój fragment kodu nie zostałby skompilowany. Odpowiedź zaktualizowana, dzięki. –

+0

@ rich-okelly nie ma za co - z przyjemnością pomożemy. –

Powiązane problemy