假设您有表
Customer
和 Purchases
,并且您希望返回来自 Knuffingen 市的所有客户及其 2023 年购买情况的 DTO。
var customers = context.Customer
.Where(c => c.City = "Knuffingen")
.ToList();
foreach (var customer in customers)
{
var purchases = customer.Purchases
.Where(p => p.Year == 2023)
.ToList();
yield return new DTO(customer, purchases);
}
这显然是一个坏主意,因为每次循环迭代都会查询数据库的新请求。
目前我正在做这样的事情:
var customers = context.Customer
.Where(c => c.City = "Knuffingen")
.ToList();
var customerIds = customer
.Select(c => c.Id)
.ToList();
var purchases = context.Purchases
.Where(p => customerIds.Contains(p.CustomerId)
&& p.Year == 2023)
.ToList();
foreach (var customer in customers)
{
var customerPurchases = purchases
.Where(p => p.CustomerId == customer.Id)
.ToList()
yield return new DTO(customer, customerPurchases);
}
但这需要考虑查询参数的最大数量,并在必要时将查询分成多个段。
我想知道是否有更好的方法,例如这样:
var customerQueryable = context.Customers
.Where(c => c.City == "Knuffingen");
var customers = customerQueryable
.ToList();
var purchases = customerQueryable
.SelectMany(c => c.Purchases
.Where(p => p.Year == 2023))
.ToList();
foreach (var customer in customers)
{
var customerPurchases = purchases
.Where(p => p.CustomerId == customer.Id)
.ToList()
yield return new DTO(customer, customerPurchases);
}
但是,如果您有更多的东西不仅仅是依赖于
Customer
实体的购买,并且您的初始过滤器有点复杂,我不确定它不会给数据库带来更大的压力来一遍又一遍地查询所有客户一遍又一遍。
为了优化查询并减少数据库压力,您可以使用预加载在单个查询中获取所有客户的购买信息。这可以通过使用实体框架中的
Include
方法来实现。
以下是如何修改代码以使用预加载的示例:
var customers = context.Customer
.Include(c => c.Purchases)
.Where(c => c.City == "Knuffingen")
.ToList();
var dtoList = new List<DTO>();
foreach (var customer in customers)
{
var customerPurchases = customer.Purchases
.Where(p => p.Year == 2023)
.ToList();
var dto = new DTO(customer, customerPurchases);
dtoList.Add(dto);
}
return dtoList;
在上面的示例中,
Include
方法用于在单个查询中急切地加载所有客户的购买情况。这样,您就无需单独查询每个客户的购买情况。
通过执行此修改后的代码,您将以更优化的方式获取客户及其购买情况,从而减少数据库的压力。