2013-04-04 27 views
0

我會對您如何看待Repository模式有所意見。經典和DDD透視圖中存儲庫的預測

在「舊」域概念(例如P of EAAA)中,存儲庫應該像一個「內存集合」,所以它應該總是返回相同的類型,所以如果你需要一個投影你必須把它,所以投影將在服務層進行例如,對吧?或者可以直接進入「域」項目?

E.g.

public class CustomerRepository 
{ 
    //Constructor accepts an IRepository<Customer> 

    public IQueryable<Customer> GetAllDebtors() 
    { 
     //Use IRepository<Customer> here to make the query 
    } 
} 

相反,國內長途,倉庫,尤其是與CQRS相結合,可以直接因爲該倉庫變成了非規範化的服務回報投影類型,對不對?

E.g.

public class CustomerDenormalizer 
{ 
    //Constructor *could* accept an IRepository<Customer> 

    public IQueryable<Debtor> GetAllDebtors() 
    { 
     //Use IRepository<Customer> here to make the query and the projection 
    } 
} 

回答

1

國際海事組織,與「內存」集合的通信是過分強調。存儲庫不應該隱藏它封裝了一些沉重的IO的事實 - 這將是一個泄漏的抽象。此外,IQueryable<T>也是一個漏洞的抽象,因爲幾乎沒有任何提供者會支持所有的操作。我建議儘可能多地將預測委託給數據庫,因爲它非常好。

CQRS中的投影有所不同。它通常作爲事件消費者實現,它更新存儲在某些底層存儲機制中的數據結構,這些存儲機制本身可能是SQL服務器或鍵值存儲。中心區別在於,在這種情況下,對來自消息隊列的事件的投影響應。這些事件可能來自外部系統。

+0

感謝,我的意思不是說在「老」的方式投射不這樣做,我的意思是服務這樣做,而不是倉庫,它是可能的,如果你傳遞一個IQueryable ,而不加載完整的對象。我更喜歡這個存儲庫也是這個預測,但我正在和一位同事討論這個問題,但這並不一致。 – 2013-04-04 15:44:54

+0

我不確定我明白你在問什麼。是否應該使用IQueryable 在內存中進行投影? – eulerfx 2013-04-04 17:14:12

+0

我的問題是,在「舊」域方法中,我可以將投影直接放入存儲庫中,因此我返回不同類型的對象(基於投影的類型),或者更好地始終返回「基本」實體鍵入並在我使用存儲庫的位置進行投影(例如,在服務層中)。顯然,這兩種方法都不應該加載完整的對象。所以問題是:從設計的角度來看,哪裏更好地進行投影?對我來說就是把它放到Repository中。 – 2013-04-04 17:24:55

1

在「舊」域概念(例如,從東亞機場聯盟的P)庫應該像一個「內存收集」,所以應該回報始終是相同的類型,所以如果你需要的投影你有要做出來,所以投影將在服務層中進行例如,對吧?

在我自己的解決方案,I keep distinct域模型(這是我從領域專家學會了語言,幾乎是一個內部DSL的C#表達式)和相關領域的應用性的擔憂(如倉庫,那應對持久化的應用需求)。這意味着它們被編碼在不同的項目中。

在這樣的結構中,我嘗試了兩種不同的方法:queryable repositories and custom ones

  • 實現IQueryable的存儲庫對於使用該域構建UI或暴露給第三方的服務的開發人員來說工作得非常好,但需要大量基礎架構工作。我們在這方面使用了不同的方法,從Linq2NHibernate到re-linq,每個方法都有優點和缺點,但每一個都相當昂貴。如果您打算使用這種技術,請定義好的指標以確保您在應用程序開發過程中保存的時間值得您花費在定製基礎架構上。
  • 自定義存儲庫(那些公開方法返回IEnumerable s)更容易設計和實現,但它們需要UI和服務的開發人員更多的努力。我們還有一個案例,根據域規則需要使用自定義存儲庫,因爲用於獲取結果的query objects也是specifications,它們也是無處不在的語言的一部分,我們(法律上)要求用於查詢的方法是同樣用來表達這樣的價值和謂語。
    但是,在自定義存儲庫中,我們也經常暴露投影方法。

或者有可能使它直接進入「域」項目?

這是可能的,但是當你有許多不同的(和非常複雜的)有界的上下文來處理時,它就變成一種痛苦。這就是爲什麼我使用不同的項目來表達無處不在的語言和適用於實踐目的的類。

相反,在DDD中,存儲庫(特別是與CQRS結合使用)可以直接返回投影類型,因爲存儲庫變成了非規範化服務,對嗎?

是的,他們可以。
即使沒有CQRS,我們也可以使用自定義存儲庫。此外,即使有一些存儲庫實施IQueryable,我們偶爾會暴露直接產生投影的方法。

+0

從我的角度來看,Repository是領域邏輯的重要組成部分,例如CustomerRepository.GetAllGreatDebtorsOrderedByOlder()實現了一個業務規則,所以我把它們放到Domain項目中。請注意,CustomerRepository不會從任何類繼承,因此它沒有基本的方法,但只有「業務方法」。 – 2013-04-06 08:24:50

+0

我建議你從存儲庫中刪除這樣的業務規則。試試像這樣:CustomerRepository.GetCustomerSatifying(greatDebtorsSpecification,OrderBy.Older)。相關的**業務**規則應該是域模型的一部分。但請注意,如果此類規則對其他**域**對象的行爲沒有影響,則這不是業務規則,這是一個應用性問題! – 2013-04-06 08:32:08

+0

我更喜歡存儲庫的特定方法,而不是規範模式,因爲更多的是面向BDD的方法,我可以像現在這樣使用規範模式。另外,因爲我的Repository在構造函數中接受了一個IRepository ,因此對持久性技術不可知。 – 2013-04-06 13:16:39

1

說「存儲庫」的「原始形式」只能返回相同實體類型的對象有些誇張。在任何時候,人們都已經在其存儲庫中包含了Count()方法或其他計算方法 - 這在Evan的藍皮書中已有記載。另一方面,我不確定「非規範化類型」是什麼意思,但是如果那是從幾個不同的實體借用來公開他們的數據或整合的類型,或者公開單個域實體的部分視圖的類型,我傾向於認爲它不再是域名。通常情況下,它們會提供特定於應用程序的用途,例如生成Excel報告或顯示統計信息或摘要屏幕。

如果是這種情況,和性能方面的原因我想利用數據庫直接而不是依賴於域的,我希望創建一個單獨的項目中,我把所有這個「報告」相關的邏輯。沒關係,如果你仍然將數據訪問對象命名爲存儲庫(畢竟它們也是對內存集合的幻想,只有其他類型的集合)。

+0

不,我認爲通過denormalised這意味着來自多個數據庫表的字段(無論是否通過視圖)。 – Chalky 2015-06-28 10:09:39

0
  • 沒有通用存儲庫。
  • 沒有IQueryable。
  • 有ICustomerRepository。
  • 讓您的CustomerRepository的具體實現充分利用底層存儲系統的所有功能。
  • 存儲庫返回預測。

    公共接口ICustomerRepository {

    公共的IEnumerable <顧客> GetAllCustomer()

    公共的IEnumerable <借方> GetAllDebtors()

    公共的IEnumerable < CustomerSummary> GetCustomerSummaryByName(字符串名稱)

    public IEnumerable < CustomerSummary> GetCustomerSumma ryById(字符串ID) }