我有一个与客户的嵌套列表结构 - >订单 - >的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
}
}
}
}
}
};
答案 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的订单。