Используя нетерпеливую загрузку с шаблоном спецификации - PullRequest
5 голосов
/ 06 декабря 2010

Я реализовал шаблон спецификации с помощью 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 / дерева выражений, необходимый для достижения этого (т. е. пример того, как это будет сделано).

Ответы [ 2 ]

3 голосов
/ 06 декабря 2010

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

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
                     };
    }
}

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

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

1 голос
/ 16 декабря 2010

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

...