How can I query a collection of objects in LINQ as a child property?

I'm new to linq and don't know how to write two simple queries. For some reason, I can't get my head around me.

its simple structure: the order has OrderItems. each orderItem has a product ID.

I would like to:

  • get all orders that ordered productId 3

  • get all orders that ordered productId 4 AND 5 in the same order.

I've tried this in several ways. two requests are at the bottom of a small test application.

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

      

+2


source to share


4 answers


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

      

+6


source


Without Linq Language-Integrated Query Syntax:

    public IEnumerable<Order> GetOrdersWithProduct(int productId)
    {
        List<Order> orders = OrderService.GetTestData();

        var result = orders.Where(o => o.Items.Any(i => i.ProductId == productId));

        return result.ToList();
    }

    public IEnumerable<Order> GetOrdersWithProduct(IEnumerable<int> productIds)
    {
        List<Order> orders = OrderService.GetTestData();

        var result = orders.Where(o => productIds.All(id => o.Items.Any(i => i.ProductId == id)));

        return result.ToList();
    }

      



Let's assume The Lame Duck is running the "Language-Integrated Query" version, so I won't do that.

+1


source


Check them out:

1.

from order in orders 
where order.Items.Exists(item => item.OrderItemId == 3)
select order

      

  1. Very similar:

    from order in orders where order.Items.Exists (item => item.OrderItemId == 3) &&
        order.Items.Exists (item => item.OrderItemId == 4) select order

0


source


    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 ) );
        var result = orders.Where(o => o.Items.Any(ii => ii.ProductId == productId));

        return result.ToList( );
    }

      

0


source







All Articles