У меня есть несколько подклассов базового типа платежной транзакции (кредитная карта, чек, наличные, billMeLater и т. Д.). Каждый подкласс имеет свой собственный репозиторий, поскольку у каждого есть свои свойства и способ выборки. Мне нужно иметь возможность искать платежные транзакции, и я пошел по пути, который привел к увеличению головной боли. Хитрость заключается в том, что иногда клиент должен искать по общим свойствам, таким как сумма или имя клиента, а иногда клиенту нужно искать по свойствам, относящимся к типу платежа, таким как номер кредитной карты или номер банковского маршрута ... но метод поиска на уровне домена должен иметь возможность возвращать все типы базы транзакций.
У меня есть следующие уровни абстракции:
Слой WCF с методом SearchTransactions ().
Доменный слой с методом SearchTransactions ().
Уровень данных с несколькими репозиториями, каждый из которых имеет метод Search ()
(зависит от типа платежа).
База данных (через EF) с типичным неразборчивым беспорядком, необходимым для DBA
Как бы вы это сделали?
EDIT:
Для дополнительного контекста, вот несколько примеров возможных типов оплаты и их базы:
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, Amount и т. Д. Одним способом. Если клиент выполняет поиск по сумме (параметр на базе), метод должен вернуть оба значения: 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; }
}
Итак, если клиент хочет выполнить поиск по общим свойствам, таким как Amount, они передают TransactionSearchCriteriaBase. Если они передают в CreditCardTransactionSearchCriteria, они заканчивают поиск транзакций по кредитным картам. Например:
var listOfTransactions = _transactionService.Search(new CreditCardTransactionSearchCriteria{ Amount = 10m, CardNumber = "1111" });
Я заменил почти неизбежный блок switch / if на фабрику хранилищ, которая возвращала список применимых хранилищ на основе типа объекта критериев, переданного фабрике.
Кроличья нора углубляется. Я хотел бы меньше кроличьей норы.
ДРУГАЯ ЧАСТЬ ИНФОРМАЦИИ:
Поскольку мы делаем это в EF 3.5, у нас нет поддержки POCO. Итак, мы не рассматриваем объекты, которые EF генерирует как объекты домена. Наши репозитории сопоставляют различные отключенные объекты EF с объектами домена и возвращают их доменным службам, которые их вызывают.