【问题标题】:How do I query a collection of objects in LINQ by a child property?如何通过子属性查询 LINQ 中的对象集合?
【发布时间】:2009-10-15 19:47:52
【问题描述】:

我是 linq 新手,无法编写两个简单的查询。由于某种原因,我无法理解它。

它是一个简单的结构:一个 Order 有 OrderItems。每个 orderItem 都有一个 productID。

我想:

  1. 获取所有订购 productId 3 的订单

  2. 获取在同一订单上订购 productId 4 和 5 的所有订单。

我已经尝试了很多方法。这两个查询位于小测试应用程序的底部。

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

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    我会这样做:

    1. 获取所有订购productId 3的订单

      var result = orders.Where(o => o.Items.Any(item => item.ProductId == 3));
      
    2. 获取所有订购 productId 4 和 5 的订单

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

    或者:

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

    然后:

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

    另一种选择:

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

    【讨论】:

    • 完美,谢谢!我想我离得太远了。有没有办法让 OrderItems 集合只有匹配的产品 ID?假设我想要一个订单集合,其中每个订单中唯一的 OrderItem 等于我传入的 productId。
    • 您的意思是要过滤掉包含任何其他产品的订单,还是要创建订单的新副本但仅包含相关产品?
    • 创建仅包含相关产品的新副本。
    • 好的,我稍后再找时间做。
    【解决方案2】:

    没有 Linq “语言集成查询”语法:

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

    看来跛脚鸭正在做“语言综合查询”版本,所以我不会这样做。

    【讨论】:

    • “没有 LINQ”的方式是什么? Where/All/Any 都是 LINQ 方法。你的意思是“不使用查询表达式语法”吗?
    • 是的,对不起,我的意思是没有 linq 集成查询。我已经在我的大多数 C# 2.0 代码中使用了这样的方法(只有一些名称差异,例如 Map/Reduce 作为 Select/Aggregate 并且显然不是扩展方法)所以我很难在这里看到任何特定于“linq”的东西它们是只是方便一些基本功能的默认定义。他们在 Sytem.Linq 命名空间中的事实对我来说似乎有点轶事。
    【解决方案3】:

    看看这些:

    1.

    from order in orders 
    where order.Items.Exists(item => item.OrderItemId == 3)
    select order
    
    1. 非常相似:

      订单中的订单 其中 order.Items.Exists(item => item.OrderItemId == 3) &&
      order.Items.Exists(item => item.OrderItemId == 4) 选择订单

    【讨论】:

      【解决方案4】:
          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( );
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多