查询c#List以限制孩子但返回父母

时间:2015-08-25 15:34:18

标签: c# linq

我有一个与客户的嵌套列表结构 - >订单 - >的OrderItems。我试图找到一个LINQ或其他查询,它将返回客户及其嵌套项目,其中OrderItem数量= 1.但是,它不应该返回任何订单或OrderItems数量!= 1。

我试过这个:

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

它只返回订单商品数量为1的客户,但它也会返回所有其他订单和订单商品。

我可以通过几个For-each循环获得所需的结果,但我想找到更优雅的东西:

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

这是对象结构和一些示例数据。

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

4 个答案:

答案 0 :(得分:2)

你正走在

的正确道路上
var customers2 = customers
    .Where(c => c.Orders.Any(o => o.OrderItems.Exists(oi => oi.Quantity == 1)));

您只需要一个额外的步骤,因为您无法同时过滤订单和客户,您已经过滤了客户以仅获得您感兴趣的客户,现在自己过滤订单

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

然而,这会留下无数的订单,而不是客户,但你不能完全按照自己的意愿行事(检索客户并更改订单属性),因为这样会改变原来的订单清单,您可以做的是创建一个匿名类型,以便在select中将订单和Customer存储在您的查询中:

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

现在你可以这样使用

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
}

答案 1 :(得分:0)

我认为这是一个较短的解决方案,但这有效:

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

但确实会创建一个新的集合。它只是遍历每个客户,使用Orders删除任何OrderItems.Count != 1,然后测试该客户是否还有Orders。如果是,则会将其添加到List<Customer>结果中。

答案 2 :(得分:0)

感谢@StripplingWarrior我觉得我已经得到了答案,但问题仍然不是最优雅的:

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;

答案 3 :(得分:0)

这将使所有客户获得订单商品数量为所需金额的特定订单。 要使用它,它将删除所有没有一个项目数量的订单项。所以你需要在使用这个函数之前克隆列表。

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

您可以像这样使用输入特定数量。

var customers2 = GetCustomersWithOrderItemQuantity(customers, 1);

如果您希望所有订单中至少有一个商品的数量为1,请使用此订单。

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

上述内容可以与其他订单相同使用,但会显示上述示例中至少有一个订单商品数量为1的订单。