1

我用我的asp.net核心web 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?你們如何讓你的資料庫正確?

+0

我建議你在codereview.stackexchange.com中提出這個問題 –

+0

那麼,存儲庫的目的是抽象出持久性。我假設'ISearchResponse'和'ISearchRequest'是彈性搜索接口。不應該在'ISearchRespository'上定義它們,因爲那麼你的持久性會泄漏到你的業​​務/域層。在這裏你應該使用自己的類,或者如果你的搜索請求足夠簡單,使用它的方法參數。當你的持久化類型泄漏到你的域中時,除了DRY – Tseng

+0

我的搜索請求涉及很多外,該存儲庫幾乎沒有用處,我已經定義了幫助類來構建它們。所以你建議我讓'repo'返回我的'SearcModel'並讓這些幫助者幫助我的'repo'? –

回答

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原則角度看問題,這是因爲:

  • 接口隔離原則被違反,因爲接口是寬(有許多方法)和這些接口的消費者不得不依賴於法說他們不沒用。
  • 違反單一責任原則,因爲存儲庫實施中的方法不具有高度一致性。與這些方法相關的唯一事實是它們屬於同一概念或實體。
  • 該設計違反開放/封閉原則,因爲幾乎每次向系統添加查詢時,都需要更改現有接口及其實現。每個接口至少有兩個實現:一個真正的實現和一個測試實現。

像這樣的設計也會導致很多痛苦,因爲很難將橫切關注點(比如安全性,審計,日誌記錄,緩存等)應用到線下。

所以這不是倉庫模式打算解決的問題;這樣的設計只是一個大的SOLID違規。

此處的解決方案是在系統中單獨建模查詢,並且不使用存儲庫,全部爲。有很多關於這方面的文章,你可以閱讀我的這篇文章here

如果我看看你的設計,它實際上與我在這裏推廣的設計有一些相似之處,因爲你似乎有一個通用的查詢方法,可以處理多種類型的查詢。查詢消息(您的ISearchRequest)似乎是Elastic Search特有的。這是你應該努力防止的事情,就像依賴倒置原則所說的那樣。

+0

我仍然在尋找你的博客文章。非常有洞察力的閱讀。快速的問題,在我的情況下,我正在構建彈性的「搜索請求」,而不是傳遞'searchText',所以在你的情況下,你會放置這樣的邏輯? 'IQuery '或'IQueryHandler '? –

+0

@ no0b:我不確定我瞭解你的問題? TQuery是可能要求的定義(包含搜索標準的消息)。使用TQuery,IQueryHandler將執行搜索並構建TResult。 – Steven

+0

我還處於'更好設計'的開始部分:)。但我的意思是'FindUsersBySearchTextQuery.SearchText'是傳遞給'controller'並用於搜索包含它的用戶名的搜索文本。有彈性,你應該從'SearchTest'建立彈性'SearchRequest'模型,以便與'_client.SearchAsync(searchRequest)'一起使用,所以我的問題是你會在'FindUsersBySearchTextQuery'或'FindUsersBySearchTextQueryHandler'或其他地方做到這一點。 –