How do I query a collection of objects in LINQ by a child property?

c#, linq

Solution

I would do it like this:

Get all orders that ordered productId 3

var result = orders.Where(o => o.Items.Any(item => item.ProductId == 3));

Get all orders that ordered productId 4 and 5

var result = orders.Where(o => o.Items.Any(item => item.ProductId == 4))
                   .Where(o => o.Items.Any(item => item.ProductId == 5));

Or:

public static IEnumerable<Order> GetOrdersWithProduct(int id)
{
    return orders.Where(o => o.Items.Any(item => item.ProductId == productId));
}

Then:

var result1 = GetOrdersWithProduct(3);
var result2 = GetOrdersWithProduct(4).Intersect(GetOrdersWithProduct(5));

Another alternative:

public static IEnumerable<Order> GetOrdersWithProducts(params int[] ids)
{
    return GetOrdersWithProducts((IEnumerable<int>) ids);
}

public static IEnumerable<Order> GetOrdersWithProducts(IEnumerable<int> ids)
{
    return orders.Where(o => !ids.Except(o.Items.Select(p => p.ProductId))
                                 .Any());
}

var result1 = GetOrdersWithProducts(3);
var result2 = GetOrdersWithProduct(4, 5);

Problem

I'm new to linq and having trouble writing two simple queries. For some reason, I cannot wrap my head around it. its a simple structure: an Order has OrderItems. each orderItem has a productID. I would like to: get all orders that ordered productId 3 get all orders that ordered productId 4 AND 5 on the same order. I've tried it a number of ways. the two queries are at the bottom of the little test app. ``` using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace test { class Program { static void Main(string[] args) { OrderService svc = new OrderService(); //find all orders that purchased ProductID 3 IEnumerable<Order> data = svc.GetOrdersWithProduct(3); //find all orders that purchase product 4 AND 5 IEnumerable<Order> data2 = svc.GetOrdersWithProduct(new int[] { 4, 5} ); } } public class Order { public int OrderId { get; set; } public IEnumerable<OrderItem> Items { get; set; } } public class OrderItem { public int OrderItemId { get; set; } public int OrderId { get; set; } public int ProductId { get; set; } } public class OrderService { private static List<Order> GetTestData() { List<Order> orders = new List<Order>(); //5 Orders, 3 items each (every orderitem has a unique product in this test set) int orderitemid = 1; int productid = 1; for (int orderid = 1; orderid < 6; orderid++) { orders.Add(new Order { OrderId = orderid, Items = new List<OrderItem> { new OrderItem() { OrderId = orderid, OrderItemId = orderitemid++, ProductId = productid ++ }, new OrderItem() { OrderId = orderid, OrderItemId = orderitemid++, ProductId = productid ++ }, new OrderItem() { OrderId = orderid, OrderItemId = orderitemid++, ProductId = productid ++ } } }); } return orders; } public IEnumerable<Order> GetOrdersWithProduct(int productId) { List<Order> orders = OrderService.GetTestData(); // ?? not really what i want, since this returns only if all items are the same var result = orders.Where(o => o.Items.All(i => i.ProductId == productId)); return result.ToList(); } public IEnumerable<Order> GetOrdersWithProduct(IEnumerable<int> productIds) { List<Order> orders = OrderService.GetTestData(); //?? var result = orders.Where(o => o.Items.All(productIds.Contains(i => i.ProductId))); return result.ToList(); } } } ```

Original source