NHibernate: избегание полных коллекций в памяти при работе с дочерними коллекциями через aggregate root

#nhibernate

#nhibernate

Вопрос:

Учитывая приведенный ниже упрощенный класс, давайте предположим:

  • у родительского элемента может быть относительно большое количество дочерних элементов (например, 1000)
  • дочерняя коллекция загружается с задержкой
  • мы загрузили один родительский элемент через его идентификатор из стандартного метода Get родительского хранилища и теперь собираемся прочитать свойство OldestChild
 class Parent 
{
       public IList<Child> Children { get; set; }

       public Child OldestChild 
       {
         get { return Children.OrderByDescending(c => c.Age).FirstOrDefault();
       }

}
  

Существует ли какой-либо наилучший практический подход при использовании NHibernate и репозиториев для удовлетворения обоих:

  • a) Следует выбрать старейшего дочернего элемента через совокупный корень (родительский) — [ie. без независимого запроса дочерней таблицы, например, через дочерний каталог с использованием родительского идентификатора]

  • b) Следует избегать загрузки всей дочерней коллекции в память (в идеале самый старый дочерний запрос должен обрабатываться БД)

Это кажется чем-то возможным и простым, но я не вижу очевидного способа достижения этого. Возможно, я что-то упускаю?

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

Ответ №1:

Я бы создал специализированный метод в вашем репозитории, который возвращает самый старый дочерний элемент данного родительского элемента.

Комментарии:

1. Да, это лучшее, что я мог придумать, и, вероятно, нормально с прагматической точки зрения. Меня беспокоило то, что это нарушает «правило» (DDD), согласно которому вы должны обращаться к дочерним объектам путем обхода коллекций родительского (совокупного корневого) объекта, а не возврата в репозиторий (см. пункт a в вопросе)

2. Я бы не рассматривал прямой доступ к дочерним объектам как антишаблон DDD, однако я бы счел, что прямое обновление дочерних объектов недопустимо. Для обеспечения соблюдения инвариантов и других бизнес-правил необходимо задействовать aggregate root. Чтение и обновление сильно отличаются, и это одна из причин, почему CQRS популярен в сообществе DDD.

3. Спасибо @Michael — пища для размышлений. Я рад, что консенсус, похоже, прямолинейный. У меня нет опыта работы с концепцией CQRS, но я также рассмотрю это в какой-то момент.

Ответ №2:

Вы могли бы сопоставить OldestChild с помощью формулы. Взгляните на это, чтобы сопоставить класс с формулой: http://blog.khedan.com/2009/01/eager-loading-from-formula-in.html