Поделиться через


Using Repository and Unit of Work patterns with Entity Framework 4.0

 


The information in this post is out of date.

Visit msdn.com/data/ef for the latest information on current and past releases of EF.


 

If you have been watching this blog, you know that I have been discussing the various aspects of POCO capabilities we 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.

If you missed the series on POCO, I’ve listed them here for your convenience. 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, I’d like to 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.

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(

Customer

 customer)
    {
        _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 typed ObjectContext).

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.

The project that includes some of the code I showed is attached to this post. Stay tuned as we’ll likely have more to say on this topic when we discuss unit testing, TDD and testability in one of our future posts.

Faisal Mohamood
Program Manager, Entity Framework

NorthwindPocoWithPatterns.zip

Comments

  • Anonymous
    June 16, 2009
    PingBack from http://aspmvc.co.cc/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-40/

  • Anonymous
    June 16, 2009
    Whats wrong with the transactionscope approach? or Why is the UnitOfWork better?

  • Anonymous
    June 16, 2009
    前回 は EF4 で追加される予定の POCO を解説しました。 V1 ではエンティティをデータ層として利用すべきか、ドメイン層で利用すべきか、という白熱した??議論がありました。 EF4 では POCO

  • Anonymous
    June 16, 2009
    9efish.感谢你的文章 - Trackback from 9eFish

  • Anonymous
    June 16, 2009
    This post covers the basic patterns used when applying Domain-driven design DDD. Domain-driven design provides a set of pattern to define domain objects and to access them in a simple way. Working with Domain-driven design sets the focus on the domain so you try to learn as much as possible about the domain and you try to put that new knowledge into the code. It avoids the gaps between business expert and developer. http://domaindrivendesign.org/resources/what_is_ddd In the last 2 years, I have been working with the newest .Net technologies (Entity Framework 3.5 and Linq2Sql) and methodologies (DDD Patterns) to find a way to simplify the creation of Data Access Layers. The result of my work is a common library that supports the developer in the folowing steps in creating a flexible Data Access Layer (DAL)

  • Simplifies the using of an ORM
  • Uses LINQ for querying data
  • Supports DDD patterns
  • Enables and simplifies TDD
  • Expandable by any data source supporting Linq
  • Supports Linq2Entities and L2Sql (NHibernate support planned)
  • Enhances missing functionalities to EF and Linq2Sql If you are interested in that library and if you are familiar with DDD, you are free to use this library to combine the newest ADO .Net technology with the DDD pattern. You can download the library under the following link: http://sourceforge.net/project/showfiles.php?group_id=242039&package_id=319519 http://sourceforge.net/projects/bbvcommon/
  • Anonymous
    June 16, 2009
    The comment has been removed

  • Anonymous
    June 16, 2009
    There's no attachment to the post

  • Anonymous
    June 16, 2009
    There is another example of this available here: http://devtalk.dk/2009/06/09/Entity+Framework+40+Beta+1+POCO+ObjectSet+Repository+And+UnitOfWork.aspx

  • Anonymous
    June 19, 2009
    Hi A question: If I have two or more changes pending, I need use "begin transaction" before call Context.SaveChanges() or it is not necesary ?

  • Anonymous
    June 20, 2009
    Thank you for submitting this cool story - Trackback from progg.ru

  • Anonymous
    June 22, 2009
    You should use interfaces for the repository variables CustomerRepository customerRepository = new CustomerRepository(unitOfWork); should be ICustomerRepository customerRepository = new CustomerRepository(unitOfWork);

  • Anonymous
    June 22, 2009
    First of all thanks for the post.  I have a question regarding your use of the Repository pattern.  If I understand correctly the purpose of the Repository is to map between your DAL and LOB to ensure true persistance ignorance.  But if you return an instance of an EF Entity object as in the example below; "    public Customer GetCustomerById(string id)    {        return _context.Customers.Where(c => c.CustomerID == id).Single();    }" Isn't that defeating the purpose of the pattern?  Why introduce the extra layer of abstraction at this point?  

  • Anonymous
    June 22, 2009
    @Keith Patton - you probably already know this but for anyone else wondering about your comment on IUnitOfWork unitOfWork = new NorthwindContext(); I guess its left to the reader to use an IoC container of ther choice rather than explitly creating a NorthwindContext. For example Unity would let you configure a mapping for IUnitOfWork to the concrete NorthwindContext. Of course this should also probably be extended to include the Repositiries.

  • Anonymous
    June 24, 2009
    @chaz He isn't necessarily returning an entity object (or type deriving from the Entity base class). The Customer type is simply a POCO and works well w/ EF4 due to it's new support for true POCO.

  • Anonymous
    August 02, 2009
    -- why we need exlicit unit of work class, where we have unit of work implemented built-in to EF?

  • Anonymous
    September 23, 2009
    your sample code below, how would you do this using dependency injection? 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();

  • Anonymous
    November 11, 2009
    @jinyen You would inject IUnitOfWork, ICustomerRepository and IProductRepository into your application layer object, e.g a Controller, Presenter or Service. (preferably through the ctor) The key would be to configre the lifetime of the UOW to be per request. This way each repo will use the same UOW/transaction. You may choose to let the UOW be handled by the infrastructure layer, and not inject it at all. If the request is good, it will commit/save, else it will rollback. (you shouldnt have to deal with that really)

  • Anonymous
    November 11, 2009
    @jinyen You would inject IUnitOfWork, ICustomerRepository and IProductRepository into your application layer object, e.g a Controller, Presenter or Service. (preferably through the ctor) The key would be to configure the lifetime of the UOW to be per request. This way each repo will use the same UOW/transaction. You may choose to let the UOW be handled by the infrastructure layer, and not inject it at all. If the request is good, it will commit/save, else it will rollback. (you shouldnt have to deal with that really)

  • Anonymous
    December 28, 2009
    So this will work as a transaction? 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(); Everything will be rollback if something goes wrong?

  • Anonymous
    March 03, 2010
    My big problem with EF it's not creating this... imagine that we have a domain object with the EF Model in it and in my Interface Layer, Business Layer and Data Access Layer I have to reference it, why? because we don't have the POCO objects and the database access in different objects. In my presentation layer I reference the project with the EF model and if I want I can do LINQ there to acess the data. I would like to create DTO objects to all database entities and create some how mapping from the EF Domain and my application domain..... this is the big problem with this...

  • Anonymous
    March 19, 2010
    Hi, just curios, why does the CustomerRepository take an IUnitOfWork?  I thought that repositories should not care about the unit of work.  CustomerRepository is a concrete class, why not just have it accept a NorthwindContext?  Its just an implementation detail anyway.  And besides its being casted immediately back to a NorthwindContext in the constructor and the IUnitOfWork interface is never used inside that class.

  • Anonymous
    April 02, 2010
    Hi, I'm tying to implement the Repository and Unit of work pattern, using Asp.Net MVC and Entity Framework 4. Please let me know if I'm doing it right... In the Models folder: Northwind.edmx Products.cs (POCO class) ProductRepository.cs (Did my product query) IProductRepository.cs NorthwindContext.cs IUnitOfWork.cs In the Controller folder: ProductController.cs (Retrieve from ProductRepository.cs and Pass it to the view) When I run the application, I'm getting error message: Mapping and metadata information could not be found for EntityType 'NorthwindMvcPoco.Models.Category'. I don't know what I'm doing wrong. I search through whole web and I couldn't resolve this issue. Please help me.

  • Anonymous
    April 26, 2010
    Wouldn't this approach leave instances/connections of the data context hanging around. I mean, shouldn't we dispose the context?

  • Anonymous
    December 23, 2010
    The best article and sample on repository and Unit of work. Crystal clear! Thank you!

  • Anonymous
    July 31, 2011
    This example is a mess up. ObjectContext already does what the "UnitOfWork" presented in this example does, all you've done here is call ObjectContext's SaveChanges() in the "UnitOfWork"'s Save() method.. I think MS is trying to fit already established enterprise patterns in wrog places, to impress young enterprise architech wannabes, maybe?.. I've come here to see a concrete example of Unit Of Work pattern in .net, but it's just fake..

  • Anonymous
    October 05, 2011

  1. What about DIIoC ? How I can resolve IUnitOfWork, ProductRepository, OrderRepository?
  2. And what about "as" operator? This is bad practicle write this: "_context = unitOfWork as NorthwindContext;"
  • Anonymous
    January 24, 2012
    @koray it just a sample about UnitOfWork. the best "sample" have to be "simple". rarely you can use a sample as pattern.

  • Anonymous
    June 28, 2012
    if there is an error in one of the repositories ,when we call the SaveChanges() none of the entries are saved. But they remain in memory and will be saved along with another code executing with the same instance of unit of work. how can we prevent this from happening?

  • Anonymous
    July 05, 2012
    @Exception Handling – This is usually what you want within a UnitOfWork, it represents one set of changes that will be applied to the database. If you want to isolate the changes made within one part of the application I would suggest using a separate UnitOfWork. Would that work in your scenario?

  • Anonymous
    January 03, 2013
    I can see no one didn't reply to Ilya (DI/IoC related) about resolving IUnitOfWork, ProductRepository, OrderRepository. I've been trying to do that for a while (using Unity) but without any luck. Any chance for some help? Thanks. btw. if I remove IUnitOfWork part out of the picture resolving becomes fairly simple. Of course I don't wont to do that.

  • Anonymous
    June 08, 2014
    I dont understand why the formatting is all over everywhere on an official msdn blog, it makes the code so hard to read

  • Anonymous
    June 10, 2014
    @vissahid - It's just that this post is over 5 years old and the theme of our blog has changed since this was posted. Per the header on this post, the content here is about EF4 and we are now up to EF6.1, so it is all out-of-date. We don't go back and keep formatting etc. updated for posts that are outdated (other than putting in the header to let readers know it is out of date).

  • Anonymous
    November 24, 2014
    "The information in this post is out of date." Cool but... Where is the latest version of this post ?!? :-)

  • Anonymous
    November 25, 2014
    @Polo - Are you wanting good ways to test with EF? If so, we've made things a lot easier in later versions by removing the need for interfaces etc.

  • Anonymous
    July 17, 2015
    Hi, I use the same technique, unitOfwork and repository, but when I update one table, it updates other tables as well. Is why? how?