Во-первых, вы должны отделить понятие предметной области от деталей реализации. Шаблон Agreagate — это то, как организовать ваш домен, а отложенная загрузка — это деталь реализации.
Кроме того, я не согласен с @Eben Roux по поводу несоответствия решений. Ленивая загрузка, на мой взгляд, ничему не противоречит. Я выражаю почему.
Ленивая загрузка себя
Чтобы понять, как можно реализовать ленивую загрузку, вы можете обратиться к шаблону PoEAAA
Мартина Фаулера 'Lazy loading'
. Для меня шаблон прокси - лучшее решение. Кроме того, важно, что большинство современных ORM поддерживает ленивую загрузку, НО для модели данных (а не для модели предметной области).
Рекомендуется разделить модель данных и модель предметной области и использовать репозитории, чтобы скрыть это преобразование:
Разделенные модели предметной области и данных
В этом случае объекты модели предметной области строятся внутри репозиториев, скрывающих контекст ORM. Требуемый объект данных и все ассоциации загружаются ORM, затем выполняется преобразование в модель предметной области и, наконец, возвращается построенный объект предметной области.
Вопрос в том, как подгружать некоторые ассоциации не при создании доменного объекта, а при его жизни. Вы можете использовать Repoisotry внутри объекта, и я не вижу в этом ничего плохого. Это будет выглядеть так:
public class Post {
private ICommentsRepository _commentsRepository;
private IList<Comments> _comments;
//necessary to perform lazy loading (repository always wroks with ids)
private IList<int> _commentIds;
//realize lazy loading
...
}
есть проблемы:
- Ваша модель теперь становится непонятной. Он содержит «техническую» информацию, такую как
_commentIds
.
- Как только вы хотите определить
ICommentsRepository
, вы заявляете, что Comment
является совокупным корнем. Если мы введем паттерн агрегации в модель предметной области, репозитории должны создаваться только для корней агрегации. Таким образом, это означает, что Comment
и Post
являются разными совокупными корнями. И возможно, что это не то, что вы хотите.
Есть лучшее решение:
public interface ICommentList {
...
}
public class CommentList : ICommentList {
...
}
public class CommentListProxy : ICommentList {
private CommentList _realCommentList;
private IList<int> _commentIds;
//realize lazy loading here using ORMs capabilities!
//don't use repository here!
}
public class Post {
private ICommentList _commentList;
...
}
Почтовый репозиторий инициирует поле _commentList
с прокси-объектом. Также необходимо сказать:
CommentListProxy
относится к уровню модели данных, а не к модели предметной области. Он использует возможности ORM для реализации ленивой загрузки.
- и поэтому не использует репозитории, поэтому вы можете рассматривать
CommentList
как часть совокупности Post
.
Единственный возможный недостаток этого подхода заключается в неявных запросах к базе данных при работе с объектами предметной области. Это должно быть понятно пользователям класса Post
.
Умные ORM
Наконец, есть виды ORM, которые позволяют вам использовать одну и ту же модель как для домена, так и для данных. Он реализует ленивую загрузку для модели предметной области так же, как и для модели данных. Взгляните на DataObjects.Net. Для некоторых случаев это хорошее решение.
person
Valentin P.
schedule
02.09.2014