How To use Repository and Unit of Work patterns with Entity Framework and other Persistence Frameworks

Have been discussing the various aspects of POCO capabilities  added to Entity Framework 4.0. POCO support makes it possible to do persistence ignorance with Entity Framework in a way that was never possible with Entity Framework 3.5.

It might be a good idea to quickly check these out.

POCO in Entity Framework : Part 1 – The Experience

POCO in Entity Framework : Part 2 – Complex Types, Deferred Loading and Explicit Loading

POCO in Entity Framework : Part 3 – Change Tracking with POCO

In this post we will take a look at how we might be able to take our example a bit further and use some of the common patterns such as Repository and Unit Of Work so that we can implement persistence specific concerns in our example.

Windows-Live-Writer_8c4963ba1fa3_CE3B_Repository_pattern_diagram_

Expanding on our Northwind based example a bit further, let’s say I am interested in supporting the following Customer entity oriented operations:

  • Query for a customer by ID
  • Searching for Customer by Name
  • Adding a new Customer to the database

I also want to be able to query for a product based on ID.

Finally, given a customer, I would like to be able to add an Order to the database

Before we get into the details, there are two things I’d like to get out of the way first:

  • There is more than one “correct” way to approach this problem. I’ll likely be making many simplifying assumptions as I go – the objective is to show a very high level sketch of how you might implement the two patterns to solve the problem at hand.
  • Normally, when using TDD, I’d start out with tests and use my tests to evolve my design incrementally. Since I’m not following TDD in this example, please bear with me if you see me doing things like defining an interface upfront, instead of letting tests and commonalities dictate the need for an interface, etc.
Implementing the Repository

Let’s start with the work we have to do on Customer entity and look at what a repository for dealing with Customer might look like:

public interface ICustomerRepository
{
Customer GetCustomerById(string id);
IEnumerable<Customer> FindByName(string name);
void AddCustomer(Customer customer);
}

This repository interface seems to meet all the requirements around Customer:

  • GetCustomerById should allow me to get a single customer entity by primary key
  • FindByName should allow me to search for customers
  • AddCustomer should allow me to add customer to the database

This sounds good to me for the moment. Defining an interface like this for your repository is a good idea, especially if you are interested in writing tests using mocks or fakes and it allows for better unit testing by keeping your database out of the equation entirely. There are blog posts coming in the future that cover testability, mocks and fakes, etc.

You might take this interface definition a bit further and define a common IRepository for dealing with concerns that are common for multiple repository types. This is fine thing to do if you see that it works for you. I don’t necessarily see the need yet for this particular example and so I’ll pass on it for now. It is entirely possible that this becomes important as you add more repositories and refactor.

Let’s take this repository and see how we might build an implementation of it that leverages Entity Framework to enable data access.

First of all, I need an ObjectContext that I can use to query for data. You might be tempted to handle ObjectContext instantiation as a part of the repository’s constructor – but it is a good idea to leave that concern out of the repository and deal with that elsewhere.

Here’s my constructor:

public CustomerRepository(NorthwindContext context)
{
if (context == null)
throw new ArgumentNullException("context");

_context = context;
}

In the above snippet, NorthwindContext is my typed ObjectContext type.

Let’s now provide implementations for the methods required by our ICustomerRepository interface.

GetCustomerById is trivial to implement, thanks to LINQ. Using standard LINQ operators, we can implement GetCustomerById like this:

public Customer GetCustomerById(string id)
{
return _context.Customers.Where(c => c.CustomerID == id).Single();
}

Similarly, FindByName could look like this. Once again, LINQ support makes this trivial to implement:

public IEnumerable<Customer> FindByName(string name)
{
return _context.Customers.Where( c => c.ContactName.StartsWith(name)
).ToList();
}

Note that I chose to expose the results as IEnumerable<T> – you might choose to expose this as an IQueryable<T> instead. There are implications to doing this – in this case, I am not interested in exposing additional IQueryable based query composition over what I return from my repository.

And finally, let’s see how we might implement AddCustomer:

public void AddCustomer(Customer customer)
{
_context.Customers.AddObject(customer);
}

You may be tempted to also implement the save functionality as a part of the AddCustomer method. While that may work for this simple example, it is generally a bad idea – this is exactly where the Unit of Work comes in and we’ll see in a bit how we can use the this pattern to allow us to implement and coordinate Save behavior.

Here’s the complete implementation of CustomerRepository that uses Entity Framework for handling persistence:

public class CustomerRepository : ICustomerRepository
{
private NorthwindContext _context;

public CustomerRepository(NorthwindContext context)
{
if (context == null)
throw new ArgumentNullException("context");

_context = context;
}

public Customer GetCustomerById(string id)
{
return _context.Customers.Where(c => c.CustomerID == id).Single();
}

public IEnumerable<Customer> FindByName(string name)
{
return _context.Customers.Where(c => c.ContactName.StartsWith(name))
.AsEnumerable<Customer>();
}

public void AddCustomer(Customercustomer)
{
_context.Customers.AddObject(customer);
}
}

Here’s how we might use the repository from client code:

CustomerRepository repository = new CustomerRepository(context);
Customer c = new Customer( ... );
repository.AddCustomer(c);
context.SaveChanges();

For dealing with my Product and Order related requirements, I could define the following interfaces (and build implementations much like CustomerRepository). I’ll leave the details out of this post for brevity.

public interface IProductRepository
{
Product GetProductById(int id);
}

public interface IOrderRepository
{
void AddOrder(Order order);
}
Implementing Unit of Work Pattern using ObjectContext

You may have noticed this already; even though we didn’t implement any specific pattern to explicitly allow us to group related operations into a unit of work, we are already getting Unit of Work functionality for free with NorthwindContext (our typedObjectContext).

The idea is that I can use the Unit of Work to group a set of related operations – the Unit of Work keeps track of the changes that I am interested in until I am ready to save them to the database. Eventually, when I am ready to save, I can do that.

I can define an interface like this to define a “Unit of Work”:

public interface IUnitOfWork
{
void Save();
}

Note that with a Unit of Work, you might also choose to implement Undo / Rollback functionality. When using Entity Framework, the recommended approach to undo is to discard your context with the changes you are interested in undoing.

I already mentioned that our typed ObjectContext (NorthwindContext) supports the Unit of Work pattern for the most part. In order to make things a bit more explicit based on the contract I just defined, I can change my NorthwindContext class to implement the IUnitOfWork interface:

public class NorthwindContext : ObjectContext, IUnitOfWork
{
public void Save()
{
SaveChanges();
}

. . .

I have to make a small adjustment to our repository implementation after this change:

public class CustomerRepository : ICustomerRepository
{
private NorthwindContext _context;

public CustomerRepository(IUnitOfWork unitOfWork)
{
if (unitOfWork == null)
throw new ArgumentNullException("unitOfWork");

_context = unitOfWork as NorthwindContext;
}

public Customer GetCustomerById(string id)
{
return _context.Customers.Where(c => c.CustomerID == id).Single();
}

public IEnumerable<Customer> FindByName(string name)
{
return _context.Customers.Where(c => c.ContactName.StartsWith(name))
.AsEnumerable<Customer>();
}

public void AddCustomer(Customer customer)
{
_context.Customers.AddObject(customer);
}
}

That’s it – we now have our IUnitOfWork friendly repository, and you can use the IUnitOfWork based context to even coordinate work across multiple repositories. Here’s an example of adding an order to the database that requires the work of multiple repositories for querying data, and ultimately saving rows back to the database:

IUnitOfWork unitOfWork = new NorthwindContext();

CustomerRepository customerRepository = new CustomerRepository(unitOfWork);
Customer customer = customerRepository.GetCustomerById("ALFKI");

ProductRepository productRepository = new ProductRepository(unitOfWork);
Product product = productRepository.GetById(1);

OrderRepository orderRepository = new OrderRepository(unitOfWork);

Order order = new Order(customer);
order.AddNewOrderDetail(product, 1);

orderRepository.AddOrder(order);

unitOfWork.Save();

What’s quite interesting to see is how little code we had to write in order to enable data access using Repository and Unit of Work patterns on top of Entity Framework. Entity Framework’s LINQ support and out of the box Unit of Work functionality makes it trivial to build repositories on top of Entity Framework.

Another thing to note is that a lot of what I’ve covered in this post has nothing to do with Entity Framework 4.0 specifically – all of these general principles will work with Entity Framework 3.5 as well. But being able to use Repository and Unit of Work like I have shown here on top of our POCO support is really telling of what’s possible in Entity Framework 4.0. I hope you find this useful.

Lastly, I’ll reiterate that there are many ways of approaching this topic, and there are many variations of solutions that will fit your needs when working with Entity Framework, Repository and Unit of Work. You might choose to implement a common IRepository interface. You might also choose to implement a Repository<TEntity> base class that gives you some common repository functionality across all your repositories.

Try some of the various approaches and see what works for you. What I’ve covered here is only a general guideline – but I hope it is enough to get you going. More importantly, I hope this shows you how it is possible to use the POCO support we have introduced in Entity Framework 4.0 to help you build a domain model that is Entity Framework friendly without needing you to compromise on the basic principles around persistence ignorance.

Another Approach using NHibernate

This is a second post in a series on unit of work and repository pattern. In first part I have discussed unit of work and generic repository pattern with linq. In this part, I’ll be unit testing the repository pattern with a simple model to achieve persistence ignorance. Lets look at the simple model that I am using for illustration purposes.

The implementation of repository pattern provided me flexibility and abstraction to achieve persistence ignorance. Some other projects needs nHibernate and linq as an implementation technology however, the project architecture made it possible to replace this implementation with another technology i.e. Entity Framework.

So, let’s not waste any time and jump into code.

namespace RepositoryPattern.Infrastructure

{

public interface IEntityKey<TKey>

{

TKey Id { get; }

}

}

IEntityKey interface is part of core infrastructure project and provides generic identity to domain model objects.

namespace RepositoryPattern.Infrastructure

{

public interface IReadOnlyRepository<TKey, TEntity> where TEntity : class, IEntityKey<TKey>

{

IQueryable<TEntity> All();

TEntity FindBy(Expression<Func<TEntity, bool>> expression);

IQueryable<TEntity> FilterBy(Expression<Func<TEntity, bool>> expression);

TEntity FindBy(TKey id);

}

}

IReadOnlyRepository provides data fetch services and exposes IQueryable interface. As you may already know that  the use of IQueryable interface is controversial. A few well respected people in .NET neighborhood expressed their data access concerns but I simply love IQueryable. I recommend you investigate these concerns and make your own decision. In my case, this interface only exposed to well defined. controlled and secure service where all these concern are dealt with. FindBy and FilterBy methods accepts Expression. The expression provides flexibility and compatibility with linq but also boosts performance by delaying the execution to achieve optimized queries to database.

 

namespace RepositoryPattern.Infrastructure

{

public interface IPersistRepository<TEntity> where TEntity : class

{

bool Add(TEntity entity);

bool Add(IEnumerable<TEntity> items);

bool Update(TEntity entity);

bool Delete(TEntity entity);

bool Delete(IEnumerable<TEntity> entities);

}

}

IPersistRepository is responsible for writing data to repository. I have separated read and write interfaces as our services may only require read only facility or vice versa.

namespace RepositoryPattern.Infrastructure

{

public interface IUnitOfWork : IDisposable

{

void Commit();

void Rollback();

}

}

IUnitOfWork interface implements unit of work pattern, encapsulates the transaction functionalities by exposing commit and rollback operations.

Now we have set-up our infrastructure abstraction, let’s implement infrastructure layer using nHibernate in a separate project called RepositoryPattern.Data.Orm.nHibernate. As I mentioned above, if we like to implement the infrastructure layer using Entity Framework; we could add another project called RepositoryPattern.Data.Orm.EntityFramework. Lets worry about nHibernate implementation using linq for now.

namespace RepositoryPattern.Data.Orm.nHibernate

{

public class Repository<TKey, T> : IPersistRepository<T>,

IReadOnlyRepository<TKey, T> where T : class, IEntityKey<TKey>

{

private readonly ISession _session;

public Repository(ISession session)

{

_session = session;

}

public bool Add(T entity)

{

_session.Save(entity);

return true;

}

public bool Add(System.Collections.Generic.IEnumerable<T> items)

{

foreach (T item in items)

{

_session.Save(item);

}

return true;

}

public bool Update(T entity)

{

_session.Update(entity);

return true;

}

public bool Delete(T entity)

{

_session.Delete(entity);

return true;

}

public bool Delete(System.Collections.Generic.IEnumerable<T> entities)

{

foreach (T entity in entities)

{

_session.Delete(entity);

}

return true;

}

public IQueryable<T> All()

{

return _session.Query<T>();

}

public T FindBy(System.Linq.Expressions.Expression<Func<T, bool>> expression)

{

return FilterBy(expression).SingleOrDefault();

}

public IQueryable<T> FilterBy(System.Linq.Expressions.Expression<Func<T, bool>> expression)

{

return All().Where(expression).AsQueryable();

}

public T FindBy(TKey id)

{

return _session.Get<T>(id);

}

}

}

Repository class implements IPersistRepository and IReadOnlyRepository interfaces. This generic implementation provides CRUD operations to all entities and keeps code DRY. The generic functionality could be extended to add entity specific logic by using Decorator Pattern.

The most important part of the implementation is a constructor of Repository class. The instance of ISession is injected via constructor injection. The injection of session instance provides flexibility to control lifetime of object via unit of work or IOC container  i.e. Castle Windsor. The session make full use of linq features supported in nHibernate 3 as shown below.

return _session.Query<T>();

Now we have repository pattern implemented, lets proceed to implement unit of work pattern.

namespace RepositoryPattern.Data.Orm.nHibernate

{

public class UnitOfWork : IUnitOfWork

{

private readonly ISessionFactory _sessionFactory;

private readonly ITransaction _transaction;

public ISession Session { get; private set; }

public UnitOfWork(ISessionFactory sessionFactory)

{

_sessionFactory = sessionFactory;

Session = _sessionFactory.OpenSession();

Session.FlushMode = FlushMode.Auto;

_transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);

}

public void Commit()

{

if (!_transaction.IsActive)

{

throw new InvalidOperationException("Oops! We don't have an active transaction");

}

_transaction.Commit();

}

public void Rollback()

{

if (_transaction.IsActive)

{

_transaction.Rollback();

}

}

public void Dispose()

{

if (Session.IsOpen)

{

Session.Close();

}

}

}

}

The implementation of IUnitOfWork is very simple and clean, again the most important part of the code is constructor. Instance of ISessionFactory is injected via constructor injection. The life time of ISessionFactory is controlled by IOC container.

The implementation of unit of work and repository pattern provides flexibility, extensibility and kept code clean and most importantly DRY.

Let’s look at the key sections of unit test code (available in BlogPostTest).

private ISessionFactory CreateConfiguration()

{

IPersistenceConfigurer persistenceConfigurer =

MsSqlConfiguration.MsSql2008.ConnectionString

(c => c.FromConnectionStringWithKey("RepositoryPatternDemo"));

Configuration cfg = persistenceConfigurer.ConfigureProperties(new Configuration());

var persistenceModel = new PersistenceModel();

var assembly = typeof(BlogPostMap).Assembly;

persistenceModel.AddMappingsFromAssembly(assembly);

persistenceModel.Configure(cfg);

return cfg.BuildSessionFactory();

}

As you may have noticed, I am using SQL Server 2008 database to test NHibernate mapping. I know you are probably thinking, why do we need database to test mappings. Well, the answer is that you don’t need a functional database to automate tests for properties, cascades and mappings with NHibernate. Ayende has written a very good post on unit testing NHibernate mappings in memory. 

[SetUp]

public void Init()

{

_unitOfWork = new UnitOfWork(_sessionFactory);

_repository = new Repository<int, BlogPost>(_unitOfWork.Session);

_post = new BlogPostBuilder()

.Title("Repository Pattern")

.SubTitle("agilefreak.workpress.com")

.Text("Unit of work and repository pattern rocks")

.PublicationDate(DateTime.Now)

.AuthorName("Naz Ali")

.Build();

}

I have initialised few members in above code. Let’s look one of the tests.

[Test]

public void Can_retrieve_blogpost_from_repository_using_linq_expression()

{

var comment = GetComment();

_post.AddCommant(comment);

_repository.Add(_post);

var savedPost = _repository.FilterBy(p => p.AuthorName == "Naz Ali"

&& p.Comments.Where(c => c.Rating > 5).Count() > 0

);

Assert.That(savedPost.Count(), Is.EqualTo(1), "Repository must return a post for given criteria");

Assert.That(savedPost.First().Id, Is.EqualTo(_post.Id), "Repository returned invalid post for given criteria");

Assert.That(savedPost.First().Comments.Count(), Is.EqualTo(1), "BlogPost must contain one comment");

}

The highlighted lines in the above code are very interesting to note here. A linq expression is passed to repository and collection result is returned. If you want to understand how nHibernate queries work, Ayende has great post on the topic available here. Here is the full source code for a test class.

namespace RepositoryPattern.Tests

{

[TestFixture]

public class BlogPostTest

{

static ISessionFactory _sessionFactory = null;

UnitOfWork _unitOfWork = null;

BlogPost _post;

Repository<int, BlogPost> _repository;

[TestFixtureSetUp]

public void Setup()

{

_sessionFactory = CreateConfiguration();

}

[SetUp]

public void Init()

{

_unitOfWork = new UnitOfWork(_sessionFactory);

_repository = new Repository<int, BlogPost>(_unitOfWork.Session);

_post = new BlogPostBuilder()

.Title("Repository Pattern")

.SubTitle("agilefreak.workpress.com")

.Text("Unit of work and repository pattern rocks")

.PublicationDate(DateTime.Now)

.AuthorName("Naz Ali")

.Build();

}

private ISessionFactory CreateConfiguration()

{

IPersistenceConfigurer persistenceConfigurer =

MsSqlConfiguration.MsSql2008.ConnectionString

(c => c.FromConnectionStringWithKey("RepositoryPatternDemo"));

Configuration cfg = persistenceConfigurer.ConfigureProperties(new Configuration());

var persistenceModel = new PersistenceModel();

var assembly = typeof(BlogPostMap).Assembly;

persistenceModel.AddMappingsFromAssembly(assembly);

persistenceModel.Configure(cfg);

return cfg.BuildSessionFactory();

}

private static Comment GetComment()

{

return new CommentBuilder()

.Email("n.ali@blog.com")

.CommentDate(DateTime.Now)

.Rating(9)

.Text("blog comment")

.Build();

}

[TearDown]

public void RollbackUnitOfWork()

{

_unitOfWork.Rollback();

_unitOfWork.Dispose();

}

[TestFixtureTearDown]

public void CleanUp()

{

_sessionFactory.Dispose();

}

[Test]

public void Can_add_blogpost_to_repository()

{

_repository.Add(_post);

var savedPost = _repository.FindBy(_post.Id);

Assert.That(savedPost, Is.Not.EqualTo(null), "Repository must return valid post for given Id");

Assert.That(savedPost.Id, Is.EqualTo(_post.Id), "Repository returned invalid post for given Id");

}

[Test]

public void Can_add_blogpost_With_Comments_to_repository()

{

var comment = GetComment();

_post.AddCommant(comment);

_repository.Add(_post);

var savedPost = _repository.FindBy(_post.Id);

Assert.That(savedPost.Comments.Count(), Is.EqualTo(1), "Repository must return post with one comment");

Assert.That(savedPost.Comments.First().Id, Is.EqualTo(comment.Id));

}

[Test]

public void Can_retrieve_blogpost_from_repository_using_linq_expression()

{

var comment = GetComment();

_post.AddCommant(comment);

_repository.Add(_post);

var savedPost = _repository.FilterBy(p => p.AuthorName == "Naz Ali"

&& p.Comments.Where(c => c.Rating > 5).Count() > 0

);

Assert.That(savedPost.Count(), Is.EqualTo(1), "Repository must return a post for given criteria");

Assert.That(savedPost.First().Id, Is.EqualTo(_post.Id), "Repository returned invalid post for given criteria");

Assert.That(savedPost.First().Comments.Count(), Is.EqualTo(1), "BlogPost must contain one comment");

}

[Test]

public void Can_Delete_Blogpost_from_repository()

{

_repository.Add(_post);

var savedPost = _repository.FindBy(_post.Id);

_repository.Delete(savedPost);

savedPost = _repository.FindBy(_post.Id);

Assert.That(savedPost, Is.EqualTo(null), "Blog post should be removed from repository");

}

}

}

The repository and unit of work patterns are both very powerful if implemented correctly. They provide a lot of flexibility, extensibility and lower the development and testing friction.

Advertisements

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 )

Google+ photo

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

Connecting to %s