存储库模式是如何真正完成的?

时间:2017-02-17 21:21:11

标签: c# elasticsearch dependency-injection asp.net-core repository-pattern

我在我的asp.net核心网络API中使用弹性搜索。在涉及到存储库责任时,我并没有完全了解这条线。

以下是我如何定义我的实现:

public SearchRespository: ISearchRespository<Product>
{
   private ElasticClient _client

   public async Task<ISearchResponse<Product>> SearchAsync(ISearchRequest request)
    {
        var response = _client.SearchAsync<Product>(request);
        return await products;
    }        

    . . . // others
}        

在我的控制器中:

public SearchController : Controller
{
    private ISearchRespository _repo;

    public SearchController(ISearchRespository repo)
    {
       _repo = repo;
    }

    public async Task<IActionResult> Search()
    {
       // build my search request from Request.Query

       var response = await _client.SearchAsync(request);
       var model = new SearchModel
       {
           Products = response.Documents;
           Aggregations = response.Aggregations;
       }

       return Ok(model)
}

目前,回购正在按原样传递弹性响应。我的问题是,我的线条正确吗?如果我只是将_client移动到我的控制器或移动构建请求并将model构建为_repo该怎么办?你们怎么得到你的存储库?

1 个答案:

答案 0 :(得分:4)

您使用弹性搜索的事实应该是一个特别是控制器不应该知道的实现细节,因此您绝对正确地将其从控制器中抽象出来。我经常看看SOLID原则,以了解我是否在正确的轨道上。如果我们查看Dependency Inversion Principle,您会看到它引导我们走向一种也被称为Ports and Adapters的风格,这基本上意味着外部工具的使用被抽象掉了(端口),并在应用程序的边界上实现连接到该第三方的Adapter

因此,从依赖倒置原则的意义上说,你已经走上正轨。

然而,Martin Fowler's Repository Pattern试图解决的问题存在很多误解。定义如下:

  

使用类似集合的界面访问域对象,在和数据映射层之间进行调解。

此处需要注意的重要一点是,域图层将使用存储库。

然而,存储库模式存在大量滥用,因为许多开发人员开始将其用作查询的分组结构。存储库是 - 我认为 - 不适用于系统中的所有查询;但仅适用于需要的查询。这些查询支持域为系统中的突变做出决策。

您系统需要的大多数查询都不是这种查询。您的代码就是一个很好的例子,因为在这种情况下,您完全跳过域并只进行读操作。

这不适合存储库。我们可以通过再次将其与SOLID原则进行比较来验证这一点。

我们假设我们有以下存储库接口:

public interface IUserRepository
{
    User[] FindUsersBySearchText(string searchText, bool includeInactiveUsers);
    User[] GetUsersByRoles(string[] roles);
    UserInfo[] GetHighUsageUsers(int reqsPerDayThreshold);
    // More methods here
}

这是一个典型的存储库抽象,您可以看到开发人员编写。从SOLID原则的角度来看,这种抽象是有问题的,因为:

  • 违反了接口隔离原则,因为接口很宽(有很多方法),并且这些接口的使用者被迫依赖于他们不使用的方法。
  • 违反了单一责任原则,因为存储库实施中的方法没有高度凝聚力。与这些方法相关的唯一事实是它们属于同一个概念或实体。
  • 设计违反了开放/封闭原则,因为几乎每次将查询添加到系统时,都需要更改现有接口及其实现。每个接口至少有两个实现:一个实际实现和一个测试实现。

这样的设计也会带来很多痛苦,因为很难在生产线上应用横切关注点(如安全性,审计,日志记录,缓存等)。

因此,这不是Repository模式旨在解决的问题;这样的设计只是一个很大的SOLID违规行为。

此处的解决方案是在您的系统中单独为查询建模,而不是在所有中使用存储库。有很多关于此的文章,您可以阅读我对here的看法。

如果我看一下你的设计,它实际上与我在这里推广的设计有一些相似之处,因为你似乎有一个可以处理许多类型查询的通用查询方法。然而,查询消息(您的ISearchRequest)似乎特定于弹性搜索。正如依赖倒置原则所述,这是你应该努力防止的事情。