3

Я реорганизую проект MVC, чтобы сделать его проверяемым. В настоящее время контроллер использует объекты контекста Entity Framework напрямую, чтобы запросить требуемые данные. Я начал абстрактно это, и он просто не работает. В конце концов у меня есть IService и абстракция IRepository, но для описания проблемы давайте просто посмотрим на IRepository. Многие люди советуют интерфейс с функциями, которые возвращают некоторые из них: IQueriable < ...>, IEnumerable < ...>, IList < ...>, SomeEntityObject, SomeDTO. Затем, когда вы хотите протестировать сервисный уровень, они могут реализовать интерфейс с классом, который не переходит в базу данных, чтобы вернуть их.Проверка платформы Entity Framework с IRepository - проблема с ленивой загрузкой

Проблема: Использование linq для объектов У меня есть ленивый (отложенный) loading в моем наборе инструментов. Это действительно очень полезно, потому что мои функции управления контроллером знают, какие данные им нужны для представления, и я не просил больше, чем нужно. Однако linq to anythingelse не имеет ленивой загрузки. Поэтому, когда мои функции IRepository возвращают любую из вышеперечисленных вещей, я теряю ленивую загрузку. Я расширил свой интерфейс такими функциями, как «GetAnything» и «GetAnythingDeep», но этого недостаточно: он должен быть намного более мелким. Который привел бы к 5-6 функциям для одного и того же типа объекта, в зависимости от свойств, которые я хочу получить в результате. Возможно, это может быть общая функция с некоторым параметром «include properties», но мне это тоже не нравится.

В конце концов, я думаю, что если я хочу, чтобы это проверялось, что приведет к значительно менее эффективному или значительно более сложному коду. Звучит не так.

Btw Я думал о том, чтобы изменить источник данных по модели сущности для xml или некоторых данных объекта, и поэтому я мог бы поддерживать linq для объектов. Я обнаружил, что он не поддерживается из коробки ... что тоже печально: это означает, что сущность framework означает источник базы данных - не очень полезная абстракция.

Конкретный пример:

Entity объектов: Статья, Язык, Личность. Отношения: Статья может содержать 1-N языков и 1 Лицо (издатель).

ViewModel object: 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 должен возвращать объект статьи с Языки включены и весь объект Person включено (его не должен знать, что в viewmodel требуется только Имя Лица). Кроме того, у меня есть 3 разных режима просмотра для статьи. Например, если кто-то хочет просмотреть список статей , тогда нет необходимости получать языки, тело и некоторые другие свойства, однако может оказаться полезным получить имя издателя (находящегося в глубине).До «проверяемого» кода действия контроллера могли просто содержать запрос linq к объектам и получать данные, которые им нужны, используя ленивую загрузку, Включить функцию, используя подзапросы, ссылаясь на внешние свойства (Publisher.Name) ... Таким образом, нет ненужного запрос к базе данных и отсутствие ненужных данных, переданных из базы данных.

Каким должен быть интерфейс IService или IRepository, чтобы получить 3-4 различных уровня объектов статьи или иногда список этих объектов?

+0

Не могли бы вы опубликовать свой код: контроллер, репозиторий и объяснить, какую часть вы хотели бы модульного тестирования? –

+0

под редакцией. я надеюсь, что это станет лучше, а не хуже :) – peterfoldi

ответ

0

Не уверен, что если вы планируете придерживаться с отложенной загрузкой, но если вы хотите гибкий способ интеграции жадной загрузки в ваше хранилище и сервисных слои сначала проверить эту статью:

http://blogs.msdn.com/b/alexj/archive/2009/07/25/tip-28-how-to-implement-include-strategies.aspx

Он в основном дает вам способ создания сильно типизированных включают стратегию так:

var strategy = new IncludeStrategy<Article>(); 
strategy.Include(a => a.Author); 

, который затем может быть передан в общий метод на вашем хранилище или слои обслуживания. Таким образом, вам не нужно иметь отдельный метод для каждого обстоятельства (т. Е. Ваш метод GetArticleDeep).

Вот метод вместилище пример использования выше, включают стратегию:

public IQueryable<Article> Find(Expression<Func<Article, bool>> criteria, IncludeStrategy<Article> includes) 
{ 
    var query = includes.ApplyTo(context.Articles).Where(criteria); 
    return query; 
} 
Смежные вопросы