Я выполняю рефакторинг проекта MVC, чтобы сделать его тестируемым.В настоящее время Контроллер использует объекты контекста Entity Framework напрямую для запроса необходимых данных.Я начал абстрагировать это, и это просто не работает.В конце концов у меня есть IService и абстракция IRepository, но для описания проблемы давайте просто посмотрим на IRepository.Многие советуют интерфейс с функциями, которые возвращают некоторые из них: IQueriable <...>, IEnumerable <...>, IList <...>, SomeEntityObject, SomeDTO .Затем, когда кто-то хочет протестировать уровень обслуживания, он может реализовать интерфейс с классом, который не отправляет их в базу данных, чтобы вернуть их.
Проблема: Использование linq для сущностей У меня есть lazy (deferred)загрузка в моем наборе инструментов.Это на самом деле очень полезно, потому что мои функции действия контроллера знают, какие данные им нужны для представления, и я не запрашивал больше, чем требовалось.Однако linq ни к чему не имеет ленивой загрузки .Поэтому, когда мои функции IRepository возвращают любую из вышеупомянутых вещей, я теряю ленивую загрузку.Я расширил свой интерфейс такими функциями, как «GetAnything» и «GetAnythingDeep» , но этого недостаточно: он должен быть гораздо более детализированным.В результате получается около 5-6 функций для одного и того же типа объекта, в зависимости от свойств, которые я хочу получить в результате.Возможно, это может быть общая функция с некоторым параметром «include properties», но мне это тоже не нравится.
В конце концов, я думаю, что если я захочу сделать его тестируемым, это приведет либо к гораздо меньшей эффективности.или гораздо более сложный код.Звучит не правильно.
Кстати, я думал о том, чтобы изменить источник данных, лежащий в основе модели сущностей, на xml или какой-либо объектный источник данных, и поэтому я мог сохранить связь с сущностями.Я обнаружил, что он не поддерживается "из коробки" ... что также печально: это означает, что структура сущностей означает источник базы данных - не очень полезная абстракция.
Конкретный пример:
Объекты сущностей: Статья, язык, личность.Отношения: Статья может иметь 1-N языков и одного человека (издатель).
Объект ViewModel: ArticleDeepViewModel: Содержит все свойства статьи, включая языки и имя человека (для просмотрастатья, поэтому не нужны другие свойства человека).
Действие контроллера, которое будет возвращать это представление, должно получить данные откуда-то.
Код до изменений:
using (var context = new Entities.Articles())
{
var article = (from a in context.Articles.Include("Languages")
where a.ID == ID
select new ViewArticleViewModel()
{
ID = a.ID,
Headline = a.Headline,
Summary = a.Summary,
Body = a.Body,
CreatedBy = a.CreatedByEntity.Name,
CreatedDate = a.CreatedDate,
Languages = (from l in context.Languages select new ViewLanguagesViewModel() { ID = l.ID, Name = l.Name, Selected = a.Languages.Contains(l) })}).Single();
this.ViewData.Model = article;
}
return View();
Код после изменений может выглядеть примерно так:
var article = ArticleService.GetArticleDeep(ID);
var viewModel = /* mapping */
this.ViewData.Model = viewModel;
return View();
Проблема заключается в том, что GetArticleDeep должен возвращать объект Article с включенными языками и всем объектом Person (он не должен знать, что модели представления требуется толькоИмя человека).Также у меня есть 3 разных модели для статьи.Например, если кто-то хочет просмотреть список статей , то нет необходимости получать языки, текст и некоторые другие свойства , однако может быть полезно получить Имя издателя (которое находится вглубоко).Перед «тестируемым» кодом действия контроллера могли бы просто содержать запрос linq to entity и получать любые необходимые данные, используя ленивую загрузку, функцию Включить , используя подзапросы, ссылаясь на внешние свойства (Publisher.Name) ... Итакнет ненужного запроса к базе данных и ненужных данных, передаваемых из базы данных.
Что должен обеспечить интерфейс IService или IRepository для получения 3-4 различных уровней объектов Article или иногда спискаэти объекты?