Вы используете репозиторий для перечисления совокупного корня. Довольно часто ваши контроллеры работают с объединенным корнем, который вы можете фильтровать, сортировать и т. Д. По требованию пользователя.
Поэтому я использую хранилище в соответствии с тем, что уже было упомянуто.
Однако иногда мне нужно работать в более сложных спецификациях, где использование совокупного корня и / или целой группы хранилищ является либо болезненным, неэффективным, либо просто невозможным. Например, вам может потребоваться запустить большой бизнес-отчет или выполнить пакетную команду.
В подобных случаях я также определил ICommand
/ IQuery
с базовой реализацией NH, чтобы заботиться о сантехнике (как это делает обобщенный Repository
).
То, что я тогда делаю, - это создаю интерфейс, который представляет контракт для спецификации, выставляя всех членов, которые мне могут понадобиться, чтобы помочь мне построить необходимые параметры. Затем я делаю реализацию этой спецификации, используя NH в качестве основы, выполняя спецификацию, используя любую технику, которая наиболее подходит (оператор HQL, необработанный SQL, Criteria, QueryOver ... что угодно).
Вот грубая иллюстрация того, что я имею в виду. Обратите внимание, что я использую произвольный ICommandProvider
, который представляет собой некоторый объект, который создает новые экземпляры команды по мере необходимости (в случае, если вам нужно выполнить несколько команд за одну операцию). Я регистрировал свои команды в IoC, и провайдер работал с ним для создания экземпляров команд.
public interface ICommand
{
}
public interface ICommandProvider
{
TCommand Create<TCommand>()
where TCommand : ICommand;
}
public interface IQuery<TResult> : ICommand
{
TResult Execute();
}
public class NhCommand : ICommand
{
// plumbing stuff here, like finding the current session
}
public class DelinquentAccountViewModel
{
public string AccountName { get; set; }
public decimal Amount { get; set; }
}
public interface IDelinquentAccountsQuery : IQuery<IEnumerable<DelinquentAccountViewModel>>
{
void AmountGreaterThan(decimal amount);
// you could define members for specifying sorting, etc. here
}
public class DelinquentAccountsQuery : NhCommand
{
public IEnumerable<DelinquentAccountViewModel> Execute()
{
// build HQL and execute results, resulting in a list of DelinquentAccountViewModels
// using _amountGreaterThan as a parameter
return null;
}
private Decimal _amountGreaterThan;
public void AmountGreaterThan(Decimal amount)
{
_amountGreaterThan = amount;
}
}
Использование в контроллере может выглядеть примерно так:
public class DelinquentAccountsController : Controller
{
protected ICommandProvider CommandProvider { get; private set; }
public DelinquentAccountsController(ICommandProvider commandProvider)
{
CommandProvider = commandProvider;
}
public ActionResult Index(decimal amount)
{
var query = CommandProvider.Create<IDelinquentAccountsQuery>();
query.AmountGreaterThan(amount);
return View(query.Execute());
}
}
Ничто не говорит о том, что вы не можете получить доступ ко всем данным с помощью команды / запроса, но это больше работы, чем мне нужно. Я считаю, что стандартный подход к хранилищу (с использованием LINQ против NHibernate) обеспечивает примерно 95% доступа к данным, который требуется моим приложениям.