5

Я реализовал шаблон спецификации с Linq, как описано здесь https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layerИспользования жадной загрузки с спецификацией шаблоном

Теперь я хочу, чтобы добавить возможность нетерпеливых нагрузок и не уверен, о лучшем способе пойти об этом.

Общий класс хранилища в связанном, например:

public IEnumerable<T> FindAll(Specification<T> specification) 
{ 
    var query = GetQuery(specification); 
    return Transact(() => query.ToList()); 
} 

public T FindOne(Specification<T> specification) 
{ 
    var query = GetQuery(specification); 
    return Transact(() => query.SingleOrDefault()); 
} 

private IQueryable<T> GetQuery(
    Specification<T> specification) 
{ 
    return session.Query<T>() 
    .Where(specification.IsSatisfiedBy()); 
} 

И реализации спецификации:

public class MoviesDirectedBy : Specification<Movie> 
{ 

private readonly string _director; 

public MoviesDirectedBy(string director) 
{ 
    _director = director; 
} 

public override 
    Expression<Func<Movie, bool>> IsSatisfiedBy() 
{ 
    return m => m.Director == _director; 
} 
} 

Это работает хорошо, теперь я хочу, чтобы добавить возможность быть в состоянии нетерпеливого нагрузки , Я понимаю, что загрузка NHibernate может быть выполнена с использованием Fetch по запросу.

Я ищу, нужно ли инкапсулировать загружаемую логику загрузки в спецификацию или передать ее в репозиторий, а также синтаксис дерева Linq/expression, необходимый для достижения этого (например, пример того, как это будет сделано).

ответ

3

Возможным решением было бы расширить класс спецификации добавить:

public virtual IEnumerable<Expression<Func<T, object>>> FetchRelated 
{ 
    get 
    { 
     return Enumerable.Empty<Expression<Func<T, object>>>(); 
    } 
} 

И изменить GetQuery к чему-то вроде:

 return specification.FetchRelated.Aggregate(
      session.Query<T>().Where(specification.IsSatisfiedBy()), 
      (current, related) => current.Fetch(related)); 

Теперь все, что вам нужно сделать, это переопределить FetchRelated при необходимости

public override IEnumerable<Expression<Func<Movie, object>>> FetchRelated 
{ 
    get 
    { 
     return new Expression<Func<Movie, object>>[] 
        { 
         m => m.RelatedEntity1, 
         m => m.RelatedEntity2 
        }; 
    } 
} 

Важным ограничением этой реализации я только что написал t hat вы можете получать только объекты, которые непосредственно связаны с корневым объектом.

Улучшение будет поддерживать произвольные уровни (с помощью ThenFetch), что потребует некоторых изменений в том, как мы работаем с обобщениями (я использовал object, чтобы комбинировать различные типы сущностей легко)

+0

Это, безусловно, решение, но это смешение обязанностей (инкапсуляция запросов и выборка стратегий). Вот почему шаблон репозитория слаб. – jason 2010-12-06 16:27:54

1

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

Смежные вопросы