2015-08-25 8 views
6

Mam zagnieżdżoną strukturę listy z klientami -> Zamówienia -> OrderItems. Próbuję znaleźć LINQ lub inne zapytanie, które zwróci Klientów i ich zagnieżdżonych elementów, gdzie OrderItem ilość = 1. Jednak nie powinien zwracać żadnych zamówień lub OrderItems, gdzie ilość! = 1.Zapytanie C# Lista do ograniczenia dzieci, ale powrót rodziców

Próbowałem to:

var customers2 = customers.Where(c => c.Orders.Any(o => o.OrderItems.Exists(oi => oi.Quantity == 1))); 

Poprawnie zwraca tylko Klientów z ilością sztuk zamówienia = 1, ale zwraca również wszystkie inne Zamówienia i Pozycje Zamówienia.

mogę uzyskać pożądane rezultaty z kilku for-each pętli, ale chciałbym znaleźć coś bardziej eleganckie:

 foreach (var customer in customers2) 
     { 
      customer.Orders = customer.Orders.Where(o => o.OrderItems.Exists(oi => oi.Quantity == 1)).ToList(); 

      foreach (var order in customer.Orders) 
      { 
       order.OrderItems = order.OrderItems.Where(oi => oi.Quantity == 1).ToList(); 
      } 
     } 

Oto struktura obiektu i niektóre dane przykładowe.

public class Customer 
{ 
    public int CustomerId { get; set; } 
    public string Name { get; set; } 
    public string Address { get; set; } 
    public List<Order> Orders { get; set; } 
} 

public class Order 
{ 
    public int OrderId { get; set; } 
    public int CustomerId { get; set; } 
    public DateTime OrderDate { get; set; } 
    public bool Shipped { get; set; } 
    public List<OrderItem> OrderItems { get; set; } 
} 

public class OrderItem 
{ 
    public int OrderItemId { get; set; } 
    public int OrderId { get; set; } 
    public string ItemName { get; set; } 
    public int Quantity { get; set; } 
} 

     var customers = new List<Customer> 
     { 
      new Customer 
      { 
       CustomerId = 1, 
       Name = "Shawn", 
       Address = "123 Main Street", 
       Orders = new List<Order>() 
       { 
        new Order() 
        { 
         OrderId = 100, 
         CustomerId = 1, 
         OrderDate = DateTime.Now, 
         Shipped = true, 
         OrderItems = new List<OrderItem>() 
         { 
          new OrderItem() 
          { 
           OrderItemId = 200, 
           OrderId = 100, 
           ItemName = "Computer", 
           Quantity = 1 
          }, 
          new OrderItem() 
          { 
           OrderItemId = 206, 
           OrderId = 100, 
           ItemName = "Hard Drive", 
           Quantity = 2 
          } 
         } 
        }, 
        new Order() 
        { 
         OrderId = 106, 
         CustomerId = 1, 
         OrderDate = DateTime.Now, 
         Shipped = true, 
         OrderItems = new List<OrderItem>() 
         { 
          new OrderItem() 
          { 
           OrderItemId = 207, 
           OrderId = 106, 
           ItemName = "Monitor", 
           Quantity = 3 
          }, 
          new OrderItem() 
          { 
           OrderItemId = 208, 
           OrderId = 106, 
           ItemName = "DVD Burner", 
           Quantity = 2 
          } 
         } 
        } 
       } 
      }, 
      new Customer 
      { 
       CustomerId = 2, 
       Name = "Arianna", 
       Address = "456 Main Street", 
       Orders = new List<Order>() 
       { 
        new Order() 
        { 
         OrderId = 101, 
         CustomerId = 2, 
         OrderDate = DateTime.Now.AddDays(-10), 
         Shipped = true, 
         OrderItems = new List<OrderItem>() 
         { 
          new OrderItem() 
          { 
           OrderItemId = 201, 
           OrderId = 101, 
           ItemName = "barbie", 
           Quantity = 2 
          } 
         } 
        } 
       } 
      }, 
      new Customer 
      { 
       CustomerId = 3, 
       Name = "Ryan", 
       Address = "789 Main Street", 
       Orders = new List<Order>() 
       { 
        new Order() 
        { 
         OrderId = 102, 
         CustomerId = 3, 
         OrderDate = DateTime.Now.AddDays(-5), 
         Shipped = true, 
         OrderItems = new List<OrderItem>() 
         { 
          new OrderItem() 
          { 
           OrderItemId = 203, 
           OrderId = 103, 
           ItemName = "Minecraft", 
           Quantity = 2 
          } 
         } 
        } 
       } 
      } 
     }; 

Odpowiedz

0

sobie wyobrazić, istnieje krócej rozwiązaniem, ale to działa:

var goodCusts = new List<Customer>(); 

foreach(var customer in customers) 
{ 
    var testCust = customer; 

    for (int i = testCust.Orders.Count - 1; i >= 0; i--) 
    { 
     if (testCust.Orders[i].OrderItems.Count != 1) 
      testCust.Orders.RemoveAt(i); 
    } 

    if (testCust.Orders.Any()) 
     goodCusts.Add(testCust);   
} 

To stwarza nową kolekcję, choć. To po prostu przechodzi przez każdego klienta, usuwa Orders z OrderItems.Count != 1, a następnie sprawdza, czy ten klient ma jakieś Orders lewo. Jeśli tak, zostanie dodany do wyników List<Customer>.

+0

Trzeba być ostrożnym z tym rozwiązaniem. Przypuśćmy, że korzystasz z ORM, może to zinterpretować usunięcie tych zamówień z listy, co oznacza, że ​​chcesz usunąć te relacje z bazy danych. – StriplingWarrior

+0

Jeśli zajdzie taka potrzeba, możesz zrobić kopię 'klienta' dla' testCust', aby obejść ten problem. – Jonesopolis

+0

Właśnie dodałem pętle foreach, które mogą sprawić, że to zadziała - po prostu próbując uzyskać coś bardziej eleganckiego ... – adova

2

Jesteś na właściwej drodze z

var customers2 = customers 
    .Where(c => c.Orders.Any(o => o.OrderItems.Exists(oi => oi.Quantity == 1))); 

Wystarczy dodatkowy krok, ponieważ nie można filtrować zleceń i klientów w tym samym czasie, to już filtrowane klientom uzyskać tylko te, jesteś zainteresowany, teraz filtrować zlecenia sami

var customers2 = customers 
    .Where(c => c.Orders.Any(o => o.OrderItems.Exists(oi => oi.Quantity == 1))) 
    .Select(c => c.Orders.Where(o => o.OrderItems(o => o.OrderItems.Exists(oi => oi.Quantity == 1))); 

to jednak pozostawia z IEnumerable z IEnumerable zleceń, a nie klienci, ale nie można zrobić dokładnie to, co chcesz (i odzyskać klientów zmieniła się ich własność zamówienia) zmieni swoją pierwotną listę zamówień, co można zrobić, to stworzyć typ anonimowy do przechowywania zarówno zlecenia i klienta w zapytaniu w select jako takie:

var customers2 = customers 
    .Where(c => c.Orders.Any(o => o.OrderItems.Exists(oi => oi.Quantity == 1))) 
    .Select(c => new 
     { 
     Customer = c, 
     FilteredOrders = c.Orders.Where(o => o.OrderItems(o => o.OrderItems.Exists(oi => oi.Quantity == 1)) 
     }); 

Teraz można używać jako takiego

foreach(var cust in customers2) 
{ 
    cust.Customer // your original Customer object 
    cust.Customer.Orders // your original orders collection for this Customer 
    cust.FilteredOrders // only the orders you're interested in for this customer 
} 
+0

To jest myślenie we właściwym kierunku. Myślę, że jest tu jeszcze jeden krok - powiedział, że nie chce, aby zwrócono "OrderItem", który miał więcej Ilości! = 1. – StriplingWarrior

0

Dzięki @StripplingWarrior myślę, że przybył na odpowiedź, choć nadal nie prob najbardziej elegancki:

var customers2 = customers.Where(x => x.Orders != null && x.Orders.Any(y => y.OrderItems != null && y.OrderItems.Any(z => z.Quantity == 1))); 

customers2.ToList().ForEach(x => 
{ 
    x.Orders.ForEach(y => 
    { 
     y.OrderItems.RemoveAll(z => z == null || z.Quantity != 1); 
    }); 

    x.Orders.RemoveAll(y => y == null || y.OrderItems.Count == 0); 
}); 

return customers2; 
+1

Przeczytaj ponownie to pytanie. Ta odpowiedź nie jest wcale tym, czego dotyczy OP. – StriplingWarrior

+0

@StriplingWarrior Po prostu edytowane na 1, źle się po raz pierwszy – codeMonkey

+1

Widzę to. To nadal nie odpowiada na pytanie. – StriplingWarrior

0

ten dostanie wszystkich klientów z konkretnych zleceń, gdzie ilość elementów zamówienia jest żądaną kwotą. Aby tego użyć, usunie wszystkie zamówienia, które nie mają jednej ilości sztuk. Musisz więc sklonować listę przed użyciem tej funkcji.

public static List<Customer> GetCustomersWithOrderItemQuantity(List<Customer> customers, int quantity) 
    { 

     var customers2 = customers.TakeWhile(c => c.Orders.Any(o => o.OrderItems.Any(oi => oi.Quantity == quantity))).ToList(); 
     customers2.ForEach(cust => cust.Orders.ForEach(o => o.OrderItems.RemoveAll(oi => oi.Quantity != quantity))); 
     return customers2; 
    } 

Możesz użyć w ten sposób, aby wprowadzić określoną ilość.

var customers2 = GetCustomersWithOrderItemQuantity(customers, 1); 

Jeśli chcesz, aby wszystkie zamówienia, w których co najmniej jeden element ma ilość 1, użyj tego.

public static IEnumerable<Customer> GetCustomersWithOrderItemQuantity(List<Customer> customers, int quantity) 
    { 
     return customers.TakeWhile(c => c.Orders.Any(o => o.OrderItems.Any(oi => oi.Quantity == quantity))); 
    } 

Powyższe może być używany tak samo jak drugi, ale pokaże wszystkie zamówienia z co najmniej jednego elementu ilości rzędu 1 W przykładzie powyżej.

Powiązane problemy