我在我的 asp.net 核心 web api 中使用 Elasticsearch 。当涉及到存储库责任时,我不太明白界限在哪里。
这是我定义我的实现的方式:
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
}
在我的 Controller 中:
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)
}
就目前而言, repo 正在按原样传递弹性响应。我的问题是我画的线对吗?如果我只是将 _client
移动到我的 Controller 或将构建请求和构造 model
移动到 _repo
会怎样?你们如何使您的存储库正确?
最佳答案
您使用 Elastic Search 的事实应该是一个实现细节,尤其是 Controller 不应该知道,因此您将其从 Controller 中抽象出来是绝对正确的。我经常查看 SOLID 原则以了解我是否在正确的轨道上。如果我们看一下 Dependency Inversion Principle , 你会看到它引导我们走向一种也被称为 Ports and Adapters 的风格,这基本上意味着外部工具的使用被抽象掉了(端口),并且在应用程序的边界上实现了一个 Adapter。连接到该第三方。
因此,从依赖倒置原则的角度来看,您的方向是正确的。
然而,人们对Martin Fowler's Repository Pattern的理解存在很多误解。正在努力解决。定义如下:
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
这里需要注意的是,存储库旨在供领域层使用。
然而,存储库模式存在很多误用,因为许多开发人员开始将其用作查询的分组结构。正如我所见,该存储库并不适用于系统中的所有查询;但仅适用于域 需要的查询。这些查询支持域为系统上的突变做出决策。
然而,您的系统需要的大多数查询都不是这种查询。您的代码就是一个很好的例子,因为在这种情况下,您完全跳过域,只执行读取操作。
这是不适合存储库的东西。我们可以通过再次将其与 SOLID 原则进行比较来验证这一点。
假设我们有以下存储库接口(interface):
public interface IUserRepository
{
User[] FindUsersBySearchText(string searchText, bool includeInactiveUsers);
User[] GetUsersByRoles(string[] roles);
UserInfo[] GetHighUsageUsers(int reqsPerDayThreshold);
// More methods here
}
这是您将看到开发人员编写的典型存储库抽象。从 SOLID 原则的角度来看,这种抽象是有问题的,因为:
- 违反了接口(interface)隔离原则,因为接口(interface)范围很广(有很多方法),并且这些接口(interface)的使用者被迫依赖于他们不使用的方法。
- 违反了单一职责原则,因为存储库实现中的方法不是高度内聚的。唯一与这些方法相关的是它们属于同一概念或实体。
- 该设计违反了开放/封闭原则,因为几乎每次向系统添加查询时,都需要更改现有接口(interface)及其实现。每个接口(interface)至少有两种实现:一种是真实实现,另一种是测试实现。
像这样的设计也会在开发过程中带来很多麻烦,因为很难应用横切关注点(如安全、审计、日志记录、缓存等)。
所以这不是 Repository 模式旨在解决的问题;这样的设计只是严重违反 SOLID。
这里的解决方案是在您的系统中单独对查询建模,完全不使用存储库。有很多关于此的文章,您可以阅读我对此的看法 here .
如果我看一下您的设计,它实际上与我在这里推广的设计有一些相似之处,因为您似乎有一个可以处理多种查询类型的通用查询方法。然而,查询消息(您的 ISearchRequest
)似乎特定于 Elastic Search。正如依赖倒置原则所述,这是您应该努力避免的事情。
关于c# - 存储库模式是如何真正完成的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42307577/