簡體   English   中英

存儲庫模式和本地化查找表

[英]Repository pattern and localized lookup tables

我試圖抓住模式存儲庫的想法,並嘗試在我已經設置的數據庫結構中實現它。 我現在正在努力獲得使用查找表的最佳實踐。 我已經創建了一個測試項目,這是我的數據庫模型:

在此輸入圖像描述

您可以看到我有三個查找表:Lookup,Language和LookupLanguage。 語言表只包含語言。

在此輸入圖像描述

查找表包含整個模型中使用的不同類型。 在此輸入圖像描述

LookupLanguage將兩個表鏈接在一起: 在此輸入圖像描述

我創建了一個新項目,所有模型都是1到1到數據庫表: 在此輸入圖像描述

我還創建了一個通用存儲庫和一個通用的CrudService接口:

public interface ICrudService<T> where T : IsActiveEntity, new()
{
    int Create(T item);
    void Save();
    void Delete(int id);
    T Get(int id);
    IEnumerable<T> GetAll();
    IEnumerable<T> Where(Expression<Func<T, bool>> func, bool showDeleted = false);
    void Restore(int id);
}

現在,根據以下帖子: 實現存儲庫模式時應該查找值/表獲取自己的存儲庫嗎? ,存儲庫應隱藏底層數據庫層。 所以我認為我需要一個服務和/或存儲庫的新實現來獲取查找,但是,我在哪里必須告訴我需要哪種語言進行查找?

讓我們從公司的狀態(新的,接受的,拒絕的)作為例子。

公司模式如下:

public partial class Company : IsActiveEntity
{
    [Required]
    [MaxLength(50)]
    public string CompanyName { get; set; }
    public System.Guid StatusGuid { get; set; }

    [ForeignKey("StatusGuid")]
    public virtual Lookup Status { get; set; }
}

我想我不需要單獨實現存儲庫? 但我需要一個單獨的實現CompanyService。

interface ICompanyService : ICrudService<Company>
{
    IQueryable<LookupLanguage> GetStatuses(Guid languageguid);
    LookupLanguage GetStatus(Guid statusguid, Guid languageguid);
}

這是正確的方法,還是我錯過了什么?

由於您的表架構和維護角度, 在您的案例中創建一個更好的選項中的Generic LookupRepository

由於名稱ICompanyService我不確定您是使用Service Locator和Repository模式還是僅使用Repository。 但無論如何,我同意存儲庫不應該總是代表表1-1,但他們大多數時間都這樣做。

您提供的SO鏈接具有與您的不同的表結構。 您有一個通用的查找表,而鏈接每個查找都有一個單獨的表。 如果您有單獨的表,那么將查找存儲庫方法與實體存儲庫一起使用是有意義的,因為您將有一個單獨的代碼來獲取每個查找的數據(因為它們具有不同模式的單獨表)。

但在您的情況下,您有一個表存儲每種語言的所有查找類型,並且有一個LookupRepository可以返回基於Language和LookupType的所有各種類型的查找。 如果在單獨的實體存儲庫中創建每個查找方法(如CompanyRepository中的GetStatuses和ContactRepository中的GetStatuses),則必須為每個存儲庫重復方法中的邏輯。

想想你是否改變了查找表的模式(比如添加一個列)並且你想要測試所有使用查找的地方,如果你在整個地方都有查找方法,那將是一場噩夢,如果你在LookupRepository中有一個方法就很容易。

interface ILookupService : ICrudService<Lookup>
{
    IQueryable<Lookup> GetStatuses(Guid languageguid, LookupType lookupType);
    Lookup GetStatus(Guid statusguid, Guid languageguid, LookupType lookupType);
}

關於你的問題,“這是正確的方法” - 這完全取決於你的具體需求。

你所做的事似乎沒有任何實際問題。 您已經使用泛型實現了存儲庫模式,這非常棒。 您正在使用存儲庫的接口,這樣可以更輕松地進行單元測試,也很棒!

您的一個標簽似乎表明您對Entity Framework感興趣。 你似乎沒有使用它。 Entity Framework將通過為您創建鍋爐板類來簡化您的代碼。 您仍然可以將存儲庫模式代碼與Entity Framework創建的類一起使用。

您似乎對服務和存儲庫的想法感到困惑。 存儲庫是一個通用對象,它允許您從商店獲取數據,而無需關心實現。 在您的示例中, ICompanyService是一個存儲庫。

這是一個非常有爭議的話題,這個問題有不同的方法。 在我們的數據邏輯中,我們沒有使用存儲庫模式,因為我們不想抽象實體框架的大部分好處。 相反,我們將上下文傳遞給業務邏輯,該業務邏輯已經是UoW / Repository模式的組合。 如果您在所有公司服務上采用這種方式,那么您的方法是可以的。 然而 ,到目前為止我所看到的,通過返回值將方法放到相關服務中是提醒它們的最佳方法。 例如,如果要獲取公司查詢,請創建ILookupService並將GetLookUpsByCompany(int companyId)方法用於檢索公司查找。

我會與相關的回應爭論。 存儲庫鏈接到數據庫實體,考慮到實體框架本身作為uow /存儲庫實現是一個最好的例子。 另一方面,服務是針對域關注的,如果數據庫實體和域實體之間存在不匹配(您有兩個單獨的層),則服務可以幫助粘合這兩者。

在您的特定情況下,您擁有存儲庫,盡管您將其稱為服務。 而且每個數據庫實體需要一個存儲庫,這更容易實現和維護。 它也有助於回答您的問題:是的,您需要鏈接表的額外存儲庫。

一個小小的建議。 您似乎有一個只接受where子句的通用查詢函數

IEnumerable<T> Where(Expression<Func<T, bool>> func, bool showDeleted = false);

如果你已經遵循允許任意過濾表達式的這條路線(這本身就有點爭論,因為有人會指出你可以'保證所有技術上可能的過濾器都可以由數據庫引擎執行),為什么你不允許所有可能的查詢,包括訂購,分頁等:

IQueryable<T> Query { get; }

這與您的版本一樣容易實現(您只是公開dbset),但允許客戶端執行更復雜的查詢,同樣可能擔心此類合同可能過於寬泛。

本地化是表示層事物。 應用程序的較低層應盡可能少地打擾它。

我看到兩種不同類型的查找:編碼概念的翻譯(先生/小姐/夫人)和實體屬性的翻譯(公司名稱可能,或職稱或產品名稱)。

編碼概念

我不會將查找表用於編碼概念。 完全沒有必要打擾下層。 您只需要為整個應用程序翻譯一次,並創建包含翻譯的簡單資源文件。

但是,如果您確實希望將翻譯保留在數據庫中,則代碼或甚至每個代碼系統的單獨查找存儲庫將排序替換資源文件並為您提供服務。

實體屬性

當某些實體具有一個或多個以不同語言翻譯的屬性時,我可以想象出不同/更糟糕的本地化問題。 然后,翻譯成為實體的一部分。 我希望存儲庫在字典中咳出包含描述的所有翻譯的實體對象。 因為查詢,緩存和更新關系時業務層不應該擔心語言。 它不應該向公司存儲庫詢問公司X的荷蘭語版本。它應該只是詢問公司X並且提供一個包含荷蘭語,英語和法語名稱的Company對象。


我還有一個關於實際數據庫實現的評論:我認為查找表會分散實際實體的注意力,甚至忘記在人與公司之間創建關系。 ;)我建議將實體屬性的所有翻譯放在一個XML類型列中。

這說明了存儲庫應該處理實體和翻譯的原因。 如果您要在某個時刻更改此存儲層級實現,即從查找表轉到xml列,則存儲庫接口應保持不變。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM