How to handle paging of sub entities with the repository pattern?
Asked Answered
D

2

7

I'm learning domain driven design. I am currently trying to write a simply application in C# designing it using DDD. This application has an aggregate root A which can contain 0..n sub entities B. This could be represented with something along the lines of:

class A {
    public int Id { get; }
    public IList<B> { get; }
}

with a repository:

class ARepository {
    public A Get(int id) { ... }
    public void SaveOrUpdate(A root) { ... }
    public void Delete(A root) { ... }
}

I would however like to add paging when presenting the B sub entities for a given A instance. How would I go about doing that? The best I can come up with is changing A and ARepository to something like:

class A {
    public int Id { get; }
}

class ARepository {
    public A Get(int id) { ... }
    public void SaveOrUpdate(A root) { ... }
    public void Delete(A root) { ... }

    public IList<B> GetBForA(A root, int offset, int pageSize, out int numPages) { ... }
}

That would work, for sure, but I would loose the simplicity and elegance of the domain model.

What is the best practice for how to handle paging of sub entities with the repository pattern? I'm not looking for how to deal with this using particular libraries, etc. but rather a way to deal with it on the "pattern level".

Douse answered 28/8, 2011 at 18:42 Comment(0)
S
3

The short answer is you should not do it like this. Repository purpose is to make accessing domain objects explicit. They should not be used to page data for UI purposes. That's completely different role which I call Finder. Why? You don't want to pollute your domain (repository belongs to domain) with UI concepts like paging. You can find a more detailed explanation here, on my blog.

Saturnalia answered 29/8, 2011 at 7:55 Comment(3)
Read your blog post and finders sounds like a good idea. So, basically, in the second example in my question, I would move the GetBForA method to a BFinder class? And what would my A domain object look like? And do the finders belong in the domain layer, as the repositories?Douse
Yep, it would end up in BFinder. Your domain object can stay as it is. In my opinion, things like this BFinder does not belong to the domain model because they serve only UI purposes.Saturnalia
@SzymonPobiega I wanted to read the blog post you mentioned but the link seems broken as it open a different website, please let us know when update the link, many thanks in advance.Biomass
H
1

If you are using an ORM like NHibernate you can achieve this by setting the collection property (IList) lazy loaded, and eagerly fetch the required page or criteria on the object itself instead of the repository. ex:

var a = ARepository.Get(1);
var secondPageOfBs = a.BList.AsQueryable()
                                          .OrderBy(c => c.Name)
                                          .Skip(PageSize * 2)
                                          .Take(PageSize)
                                          .ToList();

you can also build these queries in the repository and get the result in the domain object like:

var a = ARepository.GetWithPagedChildren(1, PageSize * 2, PageSize);

you can also build more complicated eager queries as described: http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate

Hluchy answered 28/8, 2011 at 21:8 Comment(2)
Thanks for the reply. I was, however, looking for an answer on how to handle this on the "pattern level", if you understand what I mean. Maybe it was a mistake to add C# code to the question :-).Douse
this also could help: russelleast.wordpress.com/2008/09/20/…Hluchy

© 2022 - 2024 — McMap. All rights reserved.