谁应该对分页控制器/ domail服务/存储库负责?

时间:2017-02-13 09:52:44

标签: asp.net asp.net-mvc asp.net-core asp.net-core-mvc

我的问题对于专业人士来说可能看起来很奇怪,但请考虑到我来自ruby on rails world =)

所以,我正在学习ASP.NET Core。与rails相比,我喜欢它所看到的内容。但总有那个但是......让我来描述理论问题。

假设我有Product模型。并且数据库中有超过9000条记录。很明显,我必须对它们进行分页。我已经阅读了this文章,但在我看来这里出现了问题,因为控制器不应该直接使用context。它必须使用一些存储库(但是为了简单起见,可能以这种方式提供该示例)。

所以我的问题是:谁应该对分页负责?它是否应该是从存储库接收一些可查询对象并仅采用它需要的那些记录的控制器?或者它应该是我自己的商业服务吗?或者存储库是否应该使用public IEnumerable<Product> ListProducts(int offset, int page)

之类的方法

2 个答案:

答案 0 :(得分:5)

针对此问题的一个域驱动设计解决方案是使用Specification。规范设计模式描述了对象中的查询。因此,您可以创建一个PagedProduct规范,该规范将接受任何必要的参数(pageSize,pageNumber,filter)。然后,您的一个存储库方法(通常是List()重载)将接受ISpecification,并且能够根据规范生成预期结果。这种方法有几个好处。规范有一个名称(而不是一堆LINQ),你可以推理和讨论。它可以单独进行单元测试,以确保正确性。如果您需要相同的行为(例如在MVC View操作和Web API操作上),它可以很容易地重用。

我在Pluralsight Design Patterns Library

中涵盖了规范模式

答案 1 :(得分:1)

首先,我想提醒您,您链接的所有这些示例都过于简化,因此不应该让您相信这是正确的方法。简单的事情,抽象层越少越容易监督和理解(至少在初学者的简单例子的情况下,读者可能不知道在哪里寻找什么),这就是为什么他们被这样呈现的原因。

关于这个问题:我不会说上述问题。如果我必须在它们之间做出决定,那么我会说服务和/或存储库,但这取决于您如何定义存储层等。

“以上都没有”,那么什么?我的偏好是在服务层和Web UI层之间实现中间层。服务层公开操作功能,但对于读取操作,将整个集合公开为 IQueryable ,将公开为 IEnumerable ,以便您可以利用LINQ-to-whatever-storage。

为什么我这样做,很多人可能会问。因为几乎所有的时间都会使用专门的视图模型。例如,要在管理页面上显示产品列表,您需要在products表中显示列的值,但您也很可能需要显示其类别。很少有这样的情况,您只需要从一个表中获取数据,并通过将项目公开为IQueryable<T>,您可以像Select这样做:{/ p>

public IEnumerable<ProductAdminTableViewModel> GetProducts(int page, int pageSize)
{
    backingQueryable.Select(prod => new ProductAdminTableViewModel
    {
        Id = prod.Id,
        Category = prod.Category.Name, // your provider will likely resolve this to a Join
        Name = prod.Name
    }).Skip((page - 1) * pageSize).Take(pageSize).ToList();
}

如评论所述,通过将后备存储用作IQueryable,您可以在查询到达数据库之前进行投影,从而可以避免任何讨厌的选择N + 1。

它位于中间层的原因只是您不希望在您的仓库和服务层(项目)中添加对Web项目的引用,但由于这个原因,您无法实现特定于viewmodel的查询您的服务层只是因为无法在那里解析视图模型。这意味着视图模型也驻留在同一个项目中,为此,MVC项目只包含视图,控制器和应用程序的ASP.NET MVC相关内容。我通常称这个中间层为'SolutionName.Web.Core',它引用服务层以便能够访问IQueryable<T> - 返回方法。