我正在为所有EF POCO实体使用repo模式。考虑一下,产品可能低于manu实体。我有一个视图模型,使用以下ViewModel / Dto返回有关每个产品的一些摘要信息:
ProductDto
{
public string Name { get; set; }
public string Description { get; set; }
public int NumPendingOrders { get; set; }
}
所以如果从我的仓库获得一套产品:
var products = _unitOfWork.ProductRepository.Get(filter: p => p.Name.StartsWith("S"));
var productDtos = ConvertToDto(products);
return Json(productDtos);
ConvertToDto就是这样的:
return products.Select(p => new ProductDto
{
Name = p.Name,
Description = p.Description,
NumPendingOrders = p.Orders.Count(o => o.Status == "Pending"),
});
NumPendingOrders将失败,因为我的存储库ToLists()返回的结果。我可以将ConvertToDto()函数更改为使用另一个repo:
return products.Select(p => new ProductDto
{
Name = p.Name,
Description = p.Description,
NumPendingOrders = _unitOfWork.Orders.Count(o => o.ProductId == p.Id && o.Status == "Pending"),
});
但是如果我返回1000个摘要,这个方法将导致1000次查询以获得计数。
这通常如何处理?
答案 0 :(得分:2)
首先,存储库接口永远不应泄漏其实现使用EF或其他。因此,IQueryable和暴露EF实体都不属于那里。
您告诉回购 不要如何来执行此操作。 repo将返回适合应用程序上下文的POCO(业务层的业务对象或UI的视图模型)。但是在存储库中,您正在处理EF,最好的方法是查找特定于用例的查询。
实际上,对于这种情况,将2个(或更多)查询与结果(必须确保执行查询)放入ProductDTO可能更容易。关键是这不会在回购站外显示,如果需要,你可以在内部使用手动优化查询。
答案 1 :(得分:0)
我没有针对真实的数据库进行测试,只是给你一些想法。
var products = _unitOfWork.ProductRepository.Get(filter: p => p.Name.StartsWith("S"));
var orders = _unitOfWork.OrderRepository.Get(filter: o => o.Status == "Status");
var joinList = from product in products
join order in orders on product.Id equals order.ProudctId into g
from sub in g.DefaultIfEmpty()
select new
{
Name = product.Name,
Description = product.Description,
Count = (sub == null ? 0 : 1)
};
var productDtoList = from j in joinList
group j by new {j.Name, j.Description}
into g
select new ProductDto()
{
Name = g.Key.Name,
Description = g.Key.Description,
NumPendingOrders = g.Sum(p => p.Count)
};