假设我有一个产品目录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
答案 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)