Click here to Skip to main content
15,881,424 members
Articles / Programming Languages / C# 4.0
Tip/Trick

Repository Pattern with Entity Framework 4.1 and Code First

Rate me:
Please Sign up or sign in to vote.
4.80/5 (4 votes)
7 Jan 2012CPOL2 min read 122.5K   30   17
Repository Pattern with Entity Framework 4.1 and Code First

Introduction

A popular pattern for ORM data access is the Repository pattern. Repositories are currently very popular even in EF for the reasons below:


  • Hide EF from upper layer
  • Make code better testable


The big disadvantage of EF is rigid architecture which can be hardly mocked, so if you want to unit test upper layer you must wrap EF somehow to allow mocking its implementation.

The solution I'll show is a very simple implementation of this pattern using EF 4.1 and code first to generate the database.

Using the code

We will start using a classic implementation of the Repository Pattern. In this section, I'll show a very generic one, but you can of course refactor it to be better suitable for your needs.

Below the Repository Interface

public interface IRepository<TEntity> : IDisposable where TEntity : IEntity
        {
            IQueryable<TEntity> GetAll();
            void Delete(TEntity entity);
            void Add(TEntity entity);
        } 

As you can see, we got a generic GetAll() method which returns an IQuerable that allows to retrieve and query any entity in our model. Because the Repository uses generics, we have to constrain it(as you can see, this is a TEntity).

 public interface IEntity
        {
            int Id { get; set; } 
        } 

Now let's see how to implement the repository pattern.

 public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
    {
        private IDbContext _context;
        public Repository(IDbContext context)
        {
            _context = context;
        }
          private IDbSet<TEntity> DbSet
         {
            get
            {
                return _context.Set<TEntity>();
            }
         }
          public IQueryable<TEntity> GetAll() 
          {
             return DbSet.AsQueryable(); 
          }
        public void Delete(TEntity entity)
        {
             DbSet.Remove(entity);
        }
        public void Add(TEntity entity)
        {
            DbSet.Add(entity);
        }
      
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_context != null)
                {
                    _context.Dispose();
                    _context = null;
                }
            }
        }
    } 

The repository has a constructor that takes an IDbContext object. That interface adds an abstraction layer on the EF DbContext as shown below:

 public interface IDbContext {
   
        IDbSet<TEntity> Set<TEntity>() where TEntity : class;
        int SaveChanges();
        void Dispose();
    } 


As you can see, the IDbContext has an IDbSet property. This property represents an entity set that is used to perform create, read, update, and delete operations.


In EF, when you are using code first you need to create a Context which will contain all the DbSet properties that are used to access the entities in your model. The context class must inherit from System.Data.EntityDbContext which provides facilities for querying and working with entity data as objects.
Below is the implementation of DbContext which implements the above interface and Inherits from DbContext.

public class ApplicationContext : DbContext, IDbContext
    {
        public DbSet<User> User { get; set; }
        public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
        {
            return base.Set<TEntity>();
        }
    } 

The DbContext will contain all the properties to access the entity in our context. In this example, it will access only "User". In this example, we use code first also to generate the DataBase: (only the entity that has got a relative DbSet will be generated)   

At this point, all we need to implement the repository pattern is done. At this point, we probably need to create the DataBase using code first approach.

For this scope, I have created another interface that will contain the DataBase initialization strategy.

public interface IDatabaseInitializer<in TContext> where TContext :
                   IDbContext
    {
        // Summary:
        //   Executes the strategy to initialize
        //   the database for the given context.
        // Parameters:
        //   context: The context.
        void InitializeDatabase(TContext context);
    } 

This interface is used to create the DataBase and allow the user to specify a kind of strategy. Let's assume we want to delete and create the DataBase every time we only need to implement the interface to specify what we need to do within the InitializeDatabase method as shown below:

 public class DataBaseInitializer : IDatabaseInitializer<ApplicationContext>
        {
             public void InitializeDatabase(ApplicationContext context)
            {
                context.Database.Delete();
                context.Database.Create();
            }
        } 

Now we got all we need.
First we need to initialize the DataBase (you need to add a connection string in your configuration file) as below:

<connectionStrings>
    <add
      name="PeluSoft.ApplicationContext"
      providerName="System.Data.SqlClient"
      connectionString="Server=myServer;Database=TestUser;Persist Security Info=True;"/>
  
</connectionStrings> 

At this point, we are ready to initialize the DataBase:

var context=new ApplicationContext();
var testDataBaseInitializer = new TestDataBaseInitializer();
testDataBaseInitializer.InitializeDatabase(context); 

Then you can use the repository for the common operation on the entities.

var context=new ApplicationContext();
var userRepo=new Repository<User>(context);
var user =new User()
                   {
                     Username = "TestName"
                   };
userRepo.Add(user);
context.SaveChanges(); 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect PeluSoft Limited
United Kingdom United Kingdom
I have been fascinated by software development since I was 10 years old. I'm proud of learned the first programming language with an Olivetti PC 128S based on Microsoft BASIC. I'm a Software Architect/Senior Developer with a strong background of all the developing Microsoft's technologies.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Pascualito26-Aug-15 8:22
professionalPascualito26-Aug-15 8:22 
QuestionNice Article! Question Though Pin
RonnieDean7713-Dec-13 11:24
RonnieDean7713-Dec-13 11:24 
QuestionHave you seen GenericRepository on github? Pin
Michael Freidgeim27-Dec-12 18:00
Michael Freidgeim27-Dec-12 18:00 
Have you seen https://github.com/tugberkugurlu/GenericRepository, described  at http://www.tugberkugurlu.com/archive/generic-repository-pattern-entity-framework-asp-net-mvc-and-unit-testing-triangle ?
Tugberk have done similar, but more mature implementation.
Michael Freidgeim.
Blog: http://geekswithblogs.net/mnf/

AnswerRe: Have you seen GenericRepository on github? Pin
Massimiliano Peluso "WeDev Limited"13-Mar-13 6:44
Massimiliano Peluso "WeDev Limited"13-Mar-13 6:44 
QuestionWhat about sub-classes ? Pin
Remi BOURGAREL3-Jan-12 5:16
Remi BOURGAREL3-Jan-12 5:16 
AnswerRe: What about sub-classes ? Pin
Massimiliano Peluso "WeDev Limited"3-Jan-12 5:54
Massimiliano Peluso "WeDev Limited"3-Jan-12 5:54 
GeneralRe: What about sub-classes ? Pin
Remi BOURGAREL3-Jan-12 6:03
Remi BOURGAREL3-Jan-12 6:03 
GeneralRe: What about sub-classes ? Pin
Massimiliano Peluso "WeDev Limited"3-Jan-12 22:51
Massimiliano Peluso "WeDev Limited"3-Jan-12 22:51 
GeneralRe: What about sub-classes ? Pin
Remi BOURGAREL3-Jan-12 23:34
Remi BOURGAREL3-Jan-12 23:34 
GeneralRe: What about sub-classes ? Pin
Massimiliano Peluso "WeDev Limited"3-Jan-12 23:44
Massimiliano Peluso "WeDev Limited"3-Jan-12 23:44 
GeneralRe: What about sub-classes ? Pin
rtpHarry9-Jan-12 23:00
professionalrtpHarry9-Jan-12 23:00 
GeneralRe: What about sub-classes ? Pin
Remi BOURGAREL9-Jan-12 23:29
Remi BOURGAREL9-Jan-12 23:29 
GeneralRe: What about sub-classes ? Pin
Massimiliano Peluso "WeDev Limited"10-Jan-12 0:08
Massimiliano Peluso "WeDev Limited"10-Jan-12 0:08 
SuggestionRe: What about sub-classes ? Pin
SBJ3-Jan-12 10:35
SBJ3-Jan-12 10:35 
GeneralRe: What about sub-classes ? Pin
Remi BOURGAREL3-Jan-12 23:37
Remi BOURGAREL3-Jan-12 23:37 
GeneralRe: What about sub-classes ? Pin
SBJ4-Jan-12 5:56
SBJ4-Jan-12 5:56 
GeneralRe: What about sub-classes ? Pin
Remi BOURGAREL4-Jan-12 6:27
Remi BOURGAREL4-Jan-12 6:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.