2011-08-02 31 views
4

我有幾個支付交易基類型(信用卡,支票,現金,billMeLater等)的子類。每個子類都有它自己的存儲庫,因爲每個子類都有自己的屬性和獲取方式。我需要能夠搜索付款交易,並且走了一條導致更多頭痛的道路。訣竅是有時客戶需要搜索常見的屬性,如金額或客戶名稱,有時客戶需要搜索支付類型特定的屬性,如信用卡號碼或銀行路由號碼......但域級搜索方法需要能夠返回所有類型的交易基礎。如何使用存儲庫模式搜索子類?

我有抽象以下級別:

  • 與SearchTransactions WCF層()方法。

  • 帶有SearchTransactions()方法的域圖層。

  • 具有多個存儲庫的數據層,每個存儲庫都有一個Search()方法 (支付類型特定)。

  • 數據庫(通過EF)與典型的DBA需要不知所云亂七八糟

你會怎麼做呢?

編輯:

爲了增加背景下,這裏有可能支付類型的一些例子,他們的基地:

public abstract class TransactionBase 
{ 
    public int TransactionId { get; set; } 
    public decimal Amount { get; set; } 
} 

public class CreditCardTransaction : TransactionBase 
{ 
    public string CardNumber { get; set; } 
    public int ExpirationMonth { get; set; } 
    public int ExpirationYear { get; set; } 
} 

public class CheckTransaction : TransactionBase 
{ 
    public string BankAccountNumber { get; set; } 
    public string RoutingNumber { get; set; } 
} 

因此,客戶端應該能夠在CardNumber,RoutingNumber,金額搜索等等,全部來自一種方法。如果客戶在金額上搜索(基於參數),該方法應該返回CreditCardTransaction和CheckTransaction。如果客戶在BankAccountNumber上搜索,它應該只返回CheckTransactions。

客戶的需求,並儘早解決:

客戶要求有一個呼叫搜索多種交易類型。客戶不關心他們作爲參數傳入的內容,除非他們需要多個電話來覆蓋所有支付類型。我之前的一個想法是使用帶有搜索標準的類。然後,我可以有搜索標準類的子類搜索更具體的付款類型屬性。就像這樣:

public class TransactionSearchCriteriaBase 
{ 
    public int TransactionId { get; set; } 
    public decimal Amount { get; set; } 
} 

public class CreditCardTransactionSearchCriteria : TransactionSearchCriteriaBase 
{ 
    public string CardNumber { get; set; } 
    public int ExpirationMonth { get; set; } 
    public int ExpirationYear { get; set; } 
} 

因此,如果客戶希望在像金額公共屬性進行搜索,他們通過在TransactionSearchCriteriaBase。如果他們通過CreditCardTransactionSearchCriteria,他們最終會搜索信用卡交易。例如:

var listOfTransactions = _transactionService.Search(new CreditCardTransactionSearchCriteria{ Amount = 10m, CardNumber = "1111" }); 

我取代了幾乎不可避免開關/如果與存儲庫工廠塊交回基於標準的類型適用儲存庫的清單到工廠對象通過。

兔子洞更深。我想少一個兔子洞。

信息的另一片:

由於我們在EF 3.5這樣做,我們沒有POCO的支持。所以,我們不會將EF生成的對象視爲域對象。我們的存儲庫將各種斷開連接的EF對象映射到域對象,並將它們返回給調用它們的域服務。

回答

2

我會重新考慮你的實體框架模型。

您提供的域模型看起來非常適合按類型繼承

然後你可以使用LINQ .OfType<T>()方法根據您的存儲庫中的泛型類型參數來篩選不同的交易類型,:

public class TransactionRepository : IRepository<Transaction> 
{ 
    public TTransaction Find<TTransaction>(int transactionId) 
     where TTransaction : TransactionBase, new() 
    { 
     return _ctx.Transactions.OfType<TTransaction>().SingleOrDefault(tran => tran.TransactionId == transactionId); 
    } 
} 

然後,你可以這樣做:

var ccTran = _repository.Find<CreditCardTransaction>(x => x.TransactionId == 1); 
var cTran = _repository.Find<CheckTransaction>(x => x.TransactionId == 2); 

至於您的問題:

因此,客戶端應該能夠搜索CardNumber,RoutingNu金額等,所有從一種方法

我不認爲這是可能的一種方法,當然不是沒有某種if/switch語句。

的起腳過濾 - 這一切都歸結到存儲庫方法的簽名 - 提供什麼,什麼通用的約束等

如果說每個子類型都有它自己的倉庫,然後做有一種方法可以爲所有三個存儲庫提供服務真的很有意義嗎?這種神奇的方法應該在哪裏生活?

所以總的來說,我認爲你已經達到了許多已經達到的地步,你的域名與Entity Framework對抗。

基本上,如果您在AbstractA類型的對象集上工作,則無法「向下」轉換爲DerivedA類型的對象以執行篩選。

這取決於您願意妥協多少域模型。我自己也有類似的問題,並且我最終使用TPT繼承(然後切換到TPH,因爲性能更好)。

因此,除了您提到的內容之外,您不必瞭解您的域名太多,我認爲您需要重新思考「每個子類都有自己的存儲庫,因爲每個子類都有其自己的屬性和獲取方式」。

看起來您應該在EF模型中擁有一個存儲庫TPT/TPH,並且存儲庫上的「搜索」方法對事務類型具有泛型類型約束。

如果您使用神奇的單一方法,您需要一個令人討厭的開關/ if語句,並將過濾委託給特定的方法。

+0

我想出的一個解決方案我認爲並不是很糟糕的事情就是擁有一個事務存儲庫工廠,它爲我提供了適用的事務存儲庫列表。然後我可以搜索每個回購並將結果添加到List 。思考? –

+0

客戶端需要返回多個事務類型的「神奇」方法。我寧願提供多個方法調用,因爲那樣我就可以將它全部通用化並且可以完成它。不幸的是,我被卡住了「魔法」。 –

+0

@Byron - 你可以用客戶端的一些示例調用來更新你的問題嗎? – RPM1984

1

在DDD中,聚合的主要目標是維護和管理一致性。如果我正確地按照您的示例,您有兩種類型的聚合 - 每個聚合根由CreditCardTransactionCheckTransaction代表。

但是,您所描述的場景與保持一致性無關,因爲它不會更改任何數據。你想要實現的是向用戶提供一種報告。 因此,我不會嘗試彎曲Aggregates,而是使用單一方法FindTransaction(TransactionQuery)引入另一個存儲庫 - TransactionRepository。這個回購只會存在一個原因 - 向您的數據庫查詢您需要向用戶展示的數據(是的,它將是一個只讀存儲庫)。

換句話說,當你執行一些操作來切實地改變數據,但不是僅僅向用戶顯示數據的查詢時,我會建議使用你的聚合和域實體 - 使用更簡單的對象(另外你也可以不用搞亂你的域名結構,就像在你的例子中一樣)。