使用EF存储库聚合函数

时间:2017-03-23 14:05:49

标签: c# asp.net-mvc entity-framework repository

假设我有一个产品目录MVC Web应用程序,该应用程序使用EF 6.0,其中所有CRUD操作都由存储库处理。现在,其中一个视图必须显示List Categories以及来自Products的{​​{1}}的一些汇总信息,我的意思是Category旁边名称列应显示三列,包含该类别的产品总数,以及产品的最低和最高价格。

Category

然后,如果我有一个烘焙产品库

public class Product
{
    public string   Name    { get; set; }
    public decimal  Price   { get; set; }
    public int      CategoryId             { get; set; }
    public virtual  Category    Category   { get; set; }
}

public class Category
{
    public string   Name    { get; set; }
    public virtual  ICollection<Product>   Products   { get; set; }
}

我需要显示视图

unitOfWork.ProductRepository.Insert(new Product(){Name="Doughnut", Price=4.0, CategoryId=1});
unitOfWork.ProductRepository.Insert(new Product(){Name="Apple Pie", Price=7.0, CategoryId=1});
unitOfWork.ProductRepository.Insert(new Product(){Name="Meat Pie", Price=9.0, CategoryId=1});

我不相信处理存储库查询是一个好主意,因为它破坏了使用存储库的所有想法,而AFAIK被广泛认为是一种不良做法。<登记/> 可以编写一些直接使用# Category Total Products Min Price Max Price 1 Bakery products 3 4 9 的查询,但我想知道在现实世界的应用程序中如何处理这类任务? 也许需要一个新的视图模型,然后应该添加另一个只读存储库来获取这些数据?像这样的东西?

DbContext

3 个答案:

答案 0 :(得分:0)

我不确定你的意思&#34;我不相信处理存储库查询是一个好主意,因为它破坏了使用存储库的所有想法#34 ;. 存储库背后的主要思想是抽象出数据访问。如果你想进行一些聚合,一些其他的计算或类似的事情,这主要是你的业务逻辑的一部分。 VM是要求您执行计数,最大值和最小值的组件。 VM基本上是一个抽象视图,视图通常来自业务需求。所以我认为这些查询不是数据访问的一部分,因此不是存储库的一部分。 我要做的是向存储库接口添加一个方法,如下所示:

public IQueryable<Category> GetById(int i)
{
    return dbContext.Category.Single(c=>c.CategoryId==i);
}

然后在业务逻辑中你可以像这样使用它:

unitOfWork.CategoryRepository.GetById(3).Products.Count();
unitOfWork.CategoryRepository.GetById(3).Products.Min(p=>p.Price);

这还有一个额外的好处,即不会丢失LInQ到实体的延迟执行,因此计数和寻找最小值将在数据库上执行。

答案 1 :(得分:0)

正如@Ivan Stoev已经提到的那样。 DbContext是一个存储库。它处理所有基本的CRUD操作,并且它上面的另一个存储库层似乎是多余的。你正在谈论的是什么,而不是作为一个业务层来调用存储库&#34; raw&#34;数据,应用其他逻辑并向表示层提供数据。

所以在你的情况下,你会有一个服务/商业工厂/类 - 无论你怎么称呼它 - 用这样的方法:

public IEnumerable<CategoryStatsVM> GetCategoryStats() 
{
    IList<Category> categories = dbContext.Categories.Include(m => m.Products).ToList();

    foreach (Category category in categories)
    {
        yield return new CategoryStatsVM
        {
            Name = category.Name,
            Count = category.Products.Count(),
            Products = this.GetProducts(category.Products),
            MinPrice = category.Products.Aggregate(GetMinPrice),
            MaxPrice = category.Products.Aggregate(GetMaxPrice) 
        }
    }
}

private Product GetMinPrice(Product min, Product current)
{
    return min == null || curr.Price < min.Price ? curr : min;
}

private Product GetMaxPrice(Product max, Product current)
{
    return max == null || curr.Price > max.Price ? curr : max;
}

private IEnumerable<ProductVM> GetProducts(IEnumerable<Product> products)
{
    List<ProductVM> products; // create instance of the product view model list
    return products;
}

关于最后一个功能的一个注释 - 它就在那里,因为你也应该为产品创建一个视图模型类。您不应该使用表示层中的数据模型。

我为聚合创建了单独的函数,以使其更具可读性。你当然可以通过一种方法获得所有东西:

MinPrice = category.Products.Aggregate((min, curr) => min == null || curr.Price < min.Price ? curr : min), 

答案 2 :(得分:0)

您可以使用这样的Aggregate函数来获取UserLogs上次记录事务文件

UsersLogs.Where(i => i.Id== _id).Max(x => x.transId)