簡體   English   中英

Simple Injector:將導航屬性注入存儲庫

[英]Simple Injector: injecting navigation properties into repositories

假設我們有一個實體,其中有多個相同類型的多個導航字段:

class Post : IdProvider<TPrimaryKey>
    where TKey : struct
{
    ...
    public virtual ICollection<User> LikedBy { get; set; }
    public virtual ICollection<User> SharedBy { get; set; }
}

請記住,這純粹是一個虛構的示例,可以是具有兩個相同類型的屬性的任何示例。

我目前正在為以這種方式注冊的單個實體運行基本通用存儲庫類。 定義如下所示:

EntityRepository<TKey, T> : EntityRepositoryBase, IEntityRepository<TKey, T>
    where T : class, IIdProvider<TKey> 
    where TKey : struct 

DI選擇正確的typeparam並將其注入到我的倉庫中,就像一個魅力。 我對DI很陌生,並且閱讀了這篇文章,但是仍然很難理解為什么它如此糟糕,如果它使我的生活更加輕松,並且將EF特定方法隱藏在控制器的視線之外。

然后,我有N對多的基本存儲庫類來處理兩個實體之間的關系。 也許這是一個過分的簡化,但我想認為每個多對多關系都具有主體和從屬關系,因此我將在帖子中添加喜歡/共享的用戶,而從不反對。 在我當前的實現中,基本repo類具有抽象屬性

public abstract Expression<Func<TPrincipal, ICollection<TDependent>>> GetDependentCollectionExpression { get; }

因此,我不能使基回購類成為非抽象類,並且當前必須為我的每個關系(顯式指定依賴屬性)創建此類的多個實現。

class PostToLikedUsersRepository : PrincipalToManyDependentRepository<Post, User>
{
    ...
    public override Expression<Func<Post, ICollection<User>>> GetDependentCollectionExpression
    {
        get { return item => item.LikedBy; }
    }
}

擺脫它的一種方法是通過反射來搜索具有TDependent類型的正確的TPrincipal屬性,但是在當前示例中會有很多這樣的屬性。 我從來沒有想過我怎么能為同一個委托人到從屬類型處理多個回購協議實現,因為我不確定如何讓DI向每個控制器注入每個回購協議的正確實現:一個負責喜歡,一個負責共享。

因此,我的直覺和意圖是通過某種方式對屬性選擇進行參數化。 似乎我需要在我的倉庫中注入另一個參數,以自動獲得正確的屬性,但是我不知道如何實現。 我應該在這里注入財產嗎? 但是,我應該如何以及在何處以一般方式為它選擇正確的價值? 它應該是另一個構造函數參數嗎?

我不同意本文對數據層和應用程序邏輯之間的“中介”的解釋。 調解是一種促進各層之間進行協商的行為,而不是將其隱藏/固定。 存儲庫應用於簡化應用程序邏輯和數據之間的交互。 如果您選擇了諸如Entity Framework之類的ORM作為您的數據訪問層,那么我的建議是將其提供的所有內容用於編寫代碼:

  • 編寫更簡單。
  • 更容易理解。
  • 易於維護。

通用存儲庫IMO是一種反模式,從某種意義上說,它們鼓勵開發人員將實體單獨而不是集體地視為域結構。 如果我有訂單,客戶和訂單行,是否需要每個倉庫? 如果創建訂單,則還需要創建訂單行,並將訂單與客戶相關聯。 使用通用存儲庫,我可能會有一個OrderRepository : Repository<Order>和一個Get<T>基方法,但是隨后我還需要獲取一個Customer,這是否也意味着對CustomerRepository的引用? 如何創建訂單行? 它們依賴於產品和其他元素。 如果存儲庫用於將我的應用程序邏輯與實體隔離,則意味着要使用OrderLineRepository,ProductRepository等。所有這些都只是為了創建訂單。 為了將應用程序代碼與實體等隔離開來,存儲庫不應返回實體。 如果他們這樣做,您仍然依賴於幕后EF。 如果您不在DbContext的范圍內,則延遲加載將失敗。 返回DTO是解決此問題的一種常見方法,但這會在試圖隱藏Entity Framework的同時提供數據時導致極大的效率低下和靈活性。 由於單一用途存儲庫在應用程序的不同區域之間共享,因此還會導致易碎的代碼或大量重復操作,其中每個區域不斷地需要獲取比以前的使用者更多的數據,或以稍微不同的方式獲取數據方式。 您開始在存儲庫中看到許多類似的方法,或者方法中的其他自變量,或者非常丑陋的模式,例如嘗試將表達式樹或“包含”字符串列表發送到方法中以嘗試抽象化EF可以為您做的事情。

總的來說,盡管這些依賴項看起來可能很簡單,但是協調和測試應用程序邏輯所需的代碼卻變得非常龐大和復雜。

對我來說,存儲庫具有三個主要目的:

  • 使應用程序邏輯更易於測試。 (抽象數據庫, 而不是 EF)
  • 用作工廠以確保正確初始化實體。
  • 集中底層過濾器和功能。 (IsActive,授權,多租戶,軟刪除等)

您可能會爭辯說,“工廠”責任應該屬於一個單獨的類,該類對一個或多個存儲庫具有依賴性。 從我的角度來看,存儲庫可以從DbContext訪問其所需的信息,從而使信息變得更簡單。 就是說,我的存儲庫不是泛型類,而是管理類似於我構造控制器的垂直類。 存儲庫滿足控制器的需求,即應用程序關鍵區域的需求。 我可能還有其他存儲庫來服務於其他共享的集中關注點。 (查找,身份驗證等)這有助於確保存儲庫使我的代碼易於測試,並且易於實現,因為存儲庫的實現僅出於一個目的。 對應用程序的其他可能對訂單感興趣的區域的更改不會影響我的OrderManagementRepository,該訂單管理例如為OrderManagementController服務。

該存儲庫促進或中介與EF的交互,而不是與EF分離。

暫無
暫無

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

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