// thinkbeforecoding

Repositories and IQueryable, the paging case.

2009-01-19T10:50:56 / jeremie chassaing

Edit : My opinion on this subject have changed… You can read the full story in Back on Repositories and Paging. Introducing reporting.

The technique is still useful to write the query services, but I would not recommend to implement it on a repository.

 

When it comes to repositories, people have a hard time figuring how to respect the DDD vision while taking most out of current ORM technologies (Linq and ORM) and not writing too much code – we’re so lazy.civilwar

The war between IRepository<T> generic repositories or not is raging outside, and I took some time to chose my side. Here are the points to consider :

  • The repository is a contract between the domain and the infrastructure
  • The implementation details should not leak outside

In my opinion, the first point indicates that the repository should be tailored to the domain needs. It cannot be generic, or it is not a contract at all.

When writing a contract, details matter !

This doesn’t mean that we cannot use generic tools to access data behind the interface curtain. Linq DataContext and Tables<T> are very sharp tools to implement repositories. And there is a very good post by Greg Young about that.

 

There is still a point to be discussed though :

Should the repository methods return IEnumerable<T> or IQueryable<T> ?

The IQueryable<T> is part of the framework, and cleanly integrated in the language.

The problem is that its implementation depends heavily on the underlying provider. And it is a really serious leak !

So lets state the question differently :

- Why would we need IQueryable ?
- Because we can add new query clauses, and they will be executed directly in the database.

- What kind of clause would you add ?
- Don’t know… clauses…

- Would it be business specifications ?
- No, these should already be in the repository..

- So ?
- Sorting and Paging ! These are presentation concerns !

- Here’s the point.

Paging is not a recent concern for programmers and there is never enough tools to implement it properly. The main problem is that paging once you’ve got all the data is less that effective. And this is what will happen with an IEnumerable approach.

But let’s ask a two last questions.

Why is paging useful ? Is it really a presentation concern ?

We need paging to navigate through large collection of object, and if a collection can grow enough so that is cannot be embraced in a single query, it becomes a domain concern !

  • When your object collection is known at design time to stay in small bounds but you still want to page it for presentation clarity, there is no real penalty to fetch all and display only a few.
  • But when your collection can grow big, you SHOULD provide a mechanism to retrieve only a range of it, for presentation purpose or simply for batching purpose.

The problem is that if we leak IQueryable, the user can do far more than paging, and problems can arise. So I suggest to use a new interface IPaged<T> that would provide everything needed for paging :

public interface IPaged<T> : IEnumerable<T>

    {

        ///<summary>

        /// Get the total entity count.

        ///</summary>

        int Count { get; }

 

        ///<summary>

        /// Get a range of persited entities.

        ///</summary>

        IEnumerable<T> GetRange(int index, int count);

    }

 

And here is a simple implementation on a IQueryable :

public class Paged<T> : IPaged<T>

    {

        private readonly IQueryable<T> source;

 

        public Paged(IQueryable<T> source)

        {

            this.source = source;

        }

 

 

        public IEnumerator<T> GetEnumerator()

        {

            return source.GetEnumerator();

        }

 

        IEnumerator IEnumerable.GetEnumerator()

        {

            return GetEnumerator();

        }

 

        public int Count

        {

            get { return source.Count(); }

        }

 

        public IEnumerable<T> GetRange(int index, int count)

        {

            return source.Skip(index).Take(count);

        }

    }

Then your repository can return IPaged collections like this without leaking implementation details :

public IPaged<Customer> GetCustomers();

 

This seems to be a major step in the repository pattern understanding, and it’s underlying war. And you, on which side are you ?