存储库模式和具有计数的视图模型

时间:2014-03-24 06:20:23

标签: c# entity-framework repository-pattern

我正在为所有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次查询以获得计数。

这通常如何处理?

2 个答案:

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