At first, you should separate domain concept from details of realization. Agreagate pattern is about how to organize your domain and lazy-loading is an implementation detail.
Also, I disagree with @Eben Roux about inconsistency of agreates. Lazy loading contradicts nothing in my opinion. I express why.
Lazy loading itself
To understand how lazy loading can be implemented you may refer to Martin Fowler's PoEAAA
pattern 'Lazy loading'
. For me, proxy pattern is the best solution.
Also, it's important that most nowadays ORMs supports lazy loading, BUT for data model (not domain model).
It is a good practice to separate data model and domain model and use repostiories to hide this transformation:
Separated domain and data models
In this case objects of domain model are constructed inside repositories those hide ORM context. Required data object and all associations are loaded by ORM, than transformation to domain model is performed, and finally, constructed domain object returned.
The question is how to load some associations not during creation of domain object, but during it's lifetime. You can use Repoisotry inside entity and I see nothing wrong with it. It will looks like:
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
...
}
there are problems:
- Your model now becomes not clear. It contains 'techincal' information like
_commentIds
.
- As soon as you want to define
ICommentsRepository
you claim the Comment
to be aggregate root. If we introduce agregate pattern into domain model, repositories should be creaed just for agregate roots. Thus it means that Comment
and Post
are different agregate roots. And possible that it is not what you want.
There is better solution:
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;
...
}
Post repository will initaize _commentList
field with proxy object. Also, it is necessary to say:
CommentListProxy
relates to data model layer, not to domain model. It uses ORMs capabilities to implement lazy loading
- and thus doesn't use repositories, and thus you may consider
CommentList
as a part of the Post
agregate.
The only possible disadvantage of this approach is in implicit database querying when operating with domain objects. This must be clear for users of the Post
class.
Smart ORMs
Finally there are kind of ORMs which allows you to use same model for both domain and data. It realizes lazy-loading for domain model in a same way as for data model. Take a look at DataObjects.Net. For some cases it is a good solution.