Я создаю относительно простое веб-приложение в ASP.NET MVC 4, используя Entity Framework для общения с MS SQL Server. Есть много возможностей для расширения приложения в будущем, поэтому я стремлюсь к шаблону, который максимизирует возможность повторного использования и адаптируемость в коде, чтобы сэкономить работу в будущем. Идея такая:
- Шаблон «Единица работы», чтобы избежать проблем с базой данных, фиксируя изменения только в конце каждого набора действий.
- Общий репозиторий с использованием
BaseRepository<T>
, потому что репозитории будут в основном такими же; нечетное исключение может расширять и добавлять свои дополнительные методы. - Внедрение зависимости для привязки этих репозиториев к
IRepository<T>
, которые будут использовать контроллеры, чтобы я мог переключать методы хранения данных и тому подобное с минимальными усилиями (не только для лучшей практики; есть реальная вероятность, что это произойдет). Я использую для этого Ninject.
Раньше я действительно не пробовал делать что-то подобное с нуля, поэтому я читал и думаю, что я где-то запутался. Пока у меня есть интерфейс IRepository<T>
, реализованный BaseRepository<T>
, который содержит экземпляр DataContext
, который передается в его конструктор. В этом интерфейсе есть методы для добавления, обновления, удаления и различных типов Get (одиночный по идентификатору, одиночный по предикату, группировка по предикату, все). Единственный репозиторий, который не соответствует этому интерфейсу (пока), - это репозиторий Users, который добавляет User Login(string username, string password)
для разрешения входа в систему (реализация которого обрабатывает все операции слияния, хеширования, проверки и т. Д.).
Из того, что я прочитал, теперь мне нужен класс UnitOfWork
, содержащий экземпляры всех репозиториев. Эта единица работы будет открывать репозитории, а также метод SaveChanges (). Когда я хочу манипулировать данными, я создаю экземпляр единицы работы, получаю доступ к его репозиториям (которые создаются по мере необходимости), а затем сохраняю. Если что-то выходит из строя, в базе данных ничего не меняется, потому что до единственного сохранения в конце не удастся. Все в порядке. Моя проблема в том, что все примеры, которые я могу найти, похоже, делают одно из двух:
- Некоторые передают контекст данных в единицу работы, из которой они извлекают различные репозитории. Это сводит на нет суть DI за счет наличия моего
DbContext
, специфичного для Entity-Framework (или унаследованного от него класса) в моей единице работы. - Некоторые вызывают метод Get для запроса репозитория, который является шаблоном локатора служб, который, по крайней мере, непопулярен, если не антипаттерн, и в любом случае я бы хотел избежать этого здесь.
Нужно ли мне создать интерфейс для моего источника данных и также внедрить его в единицу работы? Я не могу найти никакой документации по этому поводу, которая была бы ясной и / или достаточно полной, чтобы объяснить.
ИЗМЕНИТЬ
Я думаю, что я слишком усложнял это; Теперь я сворачиваю свой репозиторий и единицу работы в один - мой репозиторий является полностью универсальным, поэтому я просто получаю несколько общих методов (Add, Remove, Update и несколько видов Get) плюс метод SaveChanges. Это дает мне интерфейс рабочего класса; Затем у меня может быть фабричный класс, который предоставляет его экземпляры (также с интерфейсом). Если у меня также есть эта рабочая реализация IDisposable
, я могу использовать ее в блоке с ограниченной областью видимости. Итак, теперь мои контроллеры могут делать что-то вроде этого:
using (var worker = DataAccess.BeginTransaction())
{
Product item = worker.Get<Product>(p => p.ID == prodName);
//stuff...
worker.SaveChanges();
}
Если что-то пойдет не так до SaveChanges()
, все изменения отменяются, когда он выходит из блока области видимости, и рабочий объект удаляется. Я могу использовать внедрение зависимостей для предоставления конкретных реализаций поля DataAccess
, которое передается в конструктор базового контроллера. Бизнес-логика полностью реализована в контроллере и работает с IQueryable
объектами, поэтому я могу отключить DataAccess
объект-поставщик для чего угодно, если он реализует IRepository
интерфейс; нигде нет ничего специфического для Entity Framework.
Итак, есть какие-нибудь мысли по поводу этой реализации? Это на правильном пути?