Как известно, в MVC модель содержит в себе бизнес-логику приложения и, при необходимости, обеспечивает доступ к данным хранящимся в БД. При этом если учитывать, что подавляющее большинство веб приложений ASP.NET MVC строятся на основе различных СУБД, взаимодействие модели с БД становится насущной потребностью.
Ранее уже рассматривалась архитектура паттерна «Репозиторий», его реализация на C#, а также те преимущества, которые он предоставляет.
Вероятно, с первого взгляда смысл его использования покажется не совсем понятным. Ведь есть LINQ to SQL, Entity Framework и прочие ORM библиотеки, которые по сути уже реализуют весь необходимый функционал. Почему не работать в контроллерах напрямую с ними? Зачем лишние усложнения?
На самом же деле применение данного паттерна является вовсе не лишним и имеет объективные причины.
- Технология ORM не подразумевает реализацию бизнес-логики. Она всего лишь позволяет более качественно организовать взаимодействие с БД путём отображения её структуры на классы и объекты языка программирования.
В тоже время класс реализующий паттерн «Репозиторий» можно легко расширить, добавив в него необходимые функции; - Объектная модель, созданная с помощью ORM жёстко «привязана» к конкретной БД и её структуре. Паттерн «Репозиторий» позволяет изолировать работу непосредственно с БД от остальной части приложения. Это позволяет реализовать поддержку нескольких БД и даже СУБД, практически не изменяя логику работы клиентской части.
Реализация паттерна «Репозиторий» применительно к моделям в ASP.NET MVC в принципе особой сложности не представляет, хотя в ней и присутствуют некоторые особенности.
Реализация непосредственно паттерна «Репозиторий»
Так как все классы «репозитории» будут связаны с одной и той же БД, целесообразно выделить общий для всех них функционал в абстрактный базовый класс.
public abstract class Repository { protected DataContext _dc; public Repository(DataContext dc) { _dc = dc; } }
Все остальные классы будут добавлять только логику специфическую для каждого конкретного случая. Все свои основные возможности они будут получать от базового класса путём наследования (паттерн «Супертип слоя«).
public class DaysRepository : Repository { public DaysRepository(DataContext dc) : base(dc) { } public IEnumerable<vDays> GetDays() { return _dc.vDays.OrderByDescending(t => t.DayDate); } public vDays GetDay(Guid id) { return _dc.vDays.SingleOrDefault(t => t.id == id); } public void CreateDay(DateTime d) { _dc.AddNewDay(d); } public void UpdateDay (vDays v) { vDays vd = GetDay(v.id); _dc.UpdateDay(vd.id, vd.DayDate); } public void DeleteDay(Guid id) { _dc.DeleteDay(id); } }
Интеграция паттерна «Репозиторий» в проект ASP.NET MVC
Как показано выше, реализация паттерна «Репозиторий» в ASP.NET MVC действительно не представляет особого труда. В тоже время для работоспособности приложения этого недостаточно.
Необходимы инициализация подключения к БД и создание экземпляров классов «репозиториев».
Эту задачу лучше всего решить при помощи служебного класса, реализующего паттерн «ленивая загрузка».
public class DataManager { private DataContext _dc; public DataManager(string connectionString) { _dc = new DataContext(connectionString); } private DaysRepository _daysRepository; public DaysRepository Days { get { if (_daysRepository== null) { _daysRepository = new DaysRepository(_dc); } return _daysRepository; } } }
С помощью экземпляра этого класса и будет осуществляться доступ к модели в контроллере.
public class DaysController : Controller { private DataManager _dm; public DaysController(DataManager dm) { _dm = dm; } . . . }
public class SCO_ControllerFactory: DefaultControllerFactory { protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return (IController)Activator.CreateInstance(controllerType, new DataManager(WebConfigurationManager.ConnectionStrings["TestDBConnectionString"].ConnectionString;)); } }
В свою очередь, данная фабрика должна быть зарегистрирована в Global.asax.
protected void Application_Start() { . . . ControllerBuilder.Current.SetControllerFactory(new SCO_ControllerFactory()); . . . }
Только после правильного выполнения всех вышеописанных операций паттерн «Репозиторий» будет интегрирован в проект и приложение сможет выполнять свои функции.
Можно справедливо отметить, что процесс интеграции гораздо сложнее, чем сама его реализация. Но, к сожалению, эти издержки обусловлены самой архитектурой ASP.NET MVC.
Однако в любом случае положительный эффект, получаемый в результате, вполне оправдан и, если выполнить все вышеописанные операции внимательно, паттерн «Репозиторий» будет интегрирован в проект без каких-либо проблем и особых временных затрат.