How can I perform aggregate operations via the repository pattern?

I've seen various blog posts (and much conflicting advice) about the repository pattern, and so I'll start by saying that the code below is probably not following the repository pattern in many people's opinion. However, it's a common-enough implementation, and whether it adheres to Fowler's original definition or not, I'm still interested in understanding more about how this implementation is used in practice.

Suppose I have a project where data access is abstracted via an interface such as the one below, which provides basic CRUD operations.

public interface IGenericRepository<T>
{
    void Add(T entity);
    void Remove(T entity);
    void Update(T entity);
    IEnumerable<T> Fetch(Expression<Func<T,bool>> where);
}

Further suppose that I have a service layer built atop that, for example:

public class FooService
{
    private IGenericRepository<Foo> _fooRespository;

    ...

    public IEnumerable<Foo> GetBrightlyColoredFoos()
    {
        return _fooRepository.Fetch(f => f.Color == "pink" || f.Color == "yellow");
    }
}

Now suppose that I now need to know how many brightly colored Foos there are, without actually wanting to enumerate them. Ideally, I want to implement a CountBrightlyColoredFoos() method in my service, but the repository implementation gives me no way to achieve that other than by fetching them all and counting them - which is potentially very inefficient.

I could extend the repository to add a Count() method, but what about other aggregate functions that I might need, such as Min() or Max(), or Sum(), or... you get the idea.

Likewise, what if I wanted to get a list of the distinct Foo colors (SELECT DISTINCT). Again, the simple repository provides no way to do that sort of thing either.

Keeping the repository simple to make it easy to test/mock is very laudable, but how do you then address these requirements? Surely there are only two ways to go - a more complex repository, or a "back-door" for the service layer to use that bypasses the repository (and thus defeats its purpose).

Answers


I would say you need to change your design. What you want to do is have one "main" generic repository that has your basic CRUD, but also smaller repositories for each entity. You will then just have to draw a line on where to place certain operations (like sum, count, max, etc.) Most likely not all your entities are going to have to get counted, summed, etc. and most of the time you won't be able to add a generic version that applies to all entities for aggregate functions.

Base Repository:

public abstract class BaseRep<T> : IBaseRep<T> where T : class
{
   //basic CRUD
}

Foo Repository:

public class FooRep : BaseRep<Foo>, IFooRep
{
   //foo specific functions
}

Need Your Help

How to make my lightswitch application available to the internet?

networking visual-studio-lightswitch

I recently finished a lightswitch application. It's a simple POS app. I managed to install it to my own webserver created in vmware running windows 2008 im using IIS7. I can now hit the site in my

how to style a prompt text of combobox in java FX application?

css combobox javafx-2 styling

I want to modify the css style of my combobox to reduce the text-size of its promptText.