Repository Pattern – Part Three

In my previous posts; part one and part two, I introduced my take on several versions of a repository implementation. I ended up a generic repository with an IQueryable getter and insert, update and delete methods. This is good enough in most scenarios.

But I will break this into two repositories and refer you to Greg Young’s article on repositories. His implementation brings a few benefits…

  • Explicit contract
  • Flexible implementation of generic internal repository (LINQ, ADO, hql, etc…)

Take 5

I will define the generic repository contract and the explicit customer repository as below:

    public interface IRepository<T>
    {
        IList<T> FindAllBy(ISpecification<T> specification);
        void Insert(T item);
        void Delete(T item);
        void Update(T item);
    }

    public interface ICustomerRepository
    {
        Customer GetCustomerByID(string customerID);
        IList<Order> GetOrdersByCustomerID(string customerID);
        IList<Customer> GetAllCustomers();
        void Insert(Customer customer);
        void Delete(Customer customer);
        void Update(Customer customer);
    }

If you have noticed, the customer repository is the explicit contact which I have started with (See Part 1 of the series). For the keen eye, the original generic repository contract has a specification (criteria) a parameter to filter the requested entities.

Let’s define some specifications. They will be needed to filter customers by name (for the generic inner repository).

    public class AllCustomersSpecification : ISpecification<Customer>
    {
        #region Implementation of ISpecification<in Customer,out Customer>

        public IQueryable<Customer> SatisfyingElementsFrom(IQueryable<Customer> candidates)
        {
            return candidates;
        }

        #endregion
    }

    public class CustomerNameSpecification : ISpecification<Customer>
    {
        private readonly string m_name;

        public CustomerNameSpecification(string name)
        {
            m_name = name;
        }

        #region Implementation of ISpecification<in Customer,out Customer>

        public IQueryable<Customer> SatisfyingElementsFrom(IQueryable<Customer> candidates)
        {
            return candidates.Where(c => c.ContactName == m_name);
        }

        #endregion
    }

Now the implementations of the generic repository and the explicit customer repository. Customer repository is a composition.

    public class Repository<T> : IRepository<T>
    {
        // TODO: to be implemented w/ LINQ, EF, NHibernate, etc...

        #region Implementation of IRepository<T>

        public IList<T> FindAllBy(ISpecification<T> specification)
        {
            throw new NotImplementedException();
        }

        public void Insert(T item)
        {
            throw new NotImplementedException();
        }

        public void Delete(T item)
        {
            throw new NotImplementedException();
        }

        public void Update(T item)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    public class CustomerRepository : ICustomerRepository
    {
        private readonly IRepository<Customer> m_innerRepo;

        public CustomerRepository()
        {
            m_innerRepo = new Repository<Customer>();
        }
        public CustomerRepository(IRepository<Customer> repository)
        {
            m_innerRepo = repository;
        }

        #region Implementation of ICustomerRepository

        public Customer GetCustomerByID(string customerID)
        {
            return m_innerRepo.FindAllBy(new CustomerIDSpecification(customerID)).First();
        }

        public IList<Order> GetOrdersByCustomerID(string customerID)
        {
            return GetCustomerByID(customerID).Orders;
        }

        public IList<Customer> GetAllCustomers()
        {
            return m_innerRepo.FindAllBy(new AllCustomersSpecification());
        }

        public void Insert(Customer customer)
        {
            m_innerRepo.Insert(customer);
        }

        public void Delete(Customer customer)
        {
            m_innerRepo.Delete(customer);
        }

        public void Update(Customer customer)
        {
            m_innerRepo.Update(customer);
        }

        #endregion
    }

Nice thing about CustomerRepository is that it is a composition of the the generic repository. This means that a change in the implementation of generic repository does not affect the CustomerRepository since this is not inheritance anymore.

I am pretty happy with this so far.

Advertisement
Leave a comment

9 Comments

  1. “I ended up a generic repository with an IQueryable getter and insert, update and delete methods. This is good enough in most scenarios.”
    You can see more about that?

    Reply
    • You will be taking a dependency on IQueryable (System.Linq) for your repository implementation. This is neither good or bad; it will work when Linq is usable in your implementation. I just like things explicit in interfaces (method names) and generic (without a reference to a particular technology such as Linq). Like I said, there is no silver bullet and solutions makes sense in the context of the problem and environment it will be used and maintained under.

      Reply
  2. Joseph Ferris

     /  May 13, 2011

    To take it one step further, what would prevent you from providing the data-specific implementations in the actual UnitOfWork instead of the generic repository, assuming that the UoW was to be used as a context source? This would mean that you would require a UoW for *any* repository action. My repositories already require a UoW, being if the parameterless constructor is called one is created, otherwise one can be passed in (imagine multiple repositories participating in one transaction, or even nested transactions).

    Reply
    • You have great timing :) I was writing the next part in this series which covers the UoW for repositories. Your feedback is most welcome.

      Reply
      • Joseph Ferris

         /  May 13, 2011

        I am definitely interested to see what you come up with, as I am just working this out myself. ;)

        For my framework, so far, I have implemented Entities bound with Data Contracts (Data Contracts are manipulated and contain validation so that the Entity is never in an invalid state and entities just expose getters mapped to the contracts with manipulation happening either to the contract itself or through the appropriate methods on the entity), Domain Eventing, and Business Rule implementations. The project is more one to keep me thinking than anything I have immediate plans on using.

        I would imagine, though, that the UoW implementations would be the single point for the persistence to happen, as well as object hydration. The first immediate concern that I have, though, is that this means that a single UoW is bound to its implementation. So, for example, you could not mix and match data sources within a single UoW. In a real-world scenario, I am not sure how often this would occur, anyhow.

        My goal is to abstract it enough to where the impact of changing implementations is minimal, mostly in regards to the amount of code you need to write. In theory, by putting the actual implementation (NHibernate, EF, Lucene.NET, etc.) at the level of the UoW and having it use an impelemnation-specific mapper that just wraps the native object construction for each implementation, you can focus on using the code and not having to extend the infrastructure to use it, which is common in most of the approaches I have seen.

      • I use UoW when I have to persist multiple entities as batch/unit just as you described. In a most recent scenario, I used UoW in command handlers in a CQRS type of architecture.

        All the data sources are from same data source however. This should not be hard however…

      • Joseph Ferris

         /  May 13, 2011

        I don’t think it would be too hard, either, but am more wondering if it is putting too much focus on what might just be an edge case. One thought that had crossed my mind was allowing the UoW to be nestable and recursively building, since they would fall under the same ambient transaction. The part I am not convinced on is if it is needed. :)

      • You are right on that being an edge case. Keeping it as simple as possible is the best way to go in most cases I think.

  1. Repository Pattern – Part Four « Altug Sahin's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.