Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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".

like image 583
David Nordvall Avatar asked Aug 28 '11 18:08

David Nordvall


2 Answers

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.

like image 105
Szymon Pobiega Avatar answered Nov 11 '22 04:11

Szymon Pobiega


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

like image 1
Mohamed Abed Avatar answered Nov 11 '22 02:11

Mohamed Abed