Click here to Skip to main content
15,881,248 members
Articles / Web Development / ASP.NET
Tip/Trick

Generic repository pattern using EF with Dependency injection (Ninject)

Rate me:
Please Sign up or sign in to vote.
4.88/5 (12 votes)
14 May 2013CPOL4 min read 114.1K   4.8K   40   14
How to perform CRUD operations using generic repository with EF pattern with and dependency injection.

Introduction

This article explains about generic repository pattern with IocContainer and dependency injection.

Repository pattern

Repository pattern are intended to create an abstraction layer between Data Access layer and business layer so it can help to insulate application from changes in the data store and can facilitate automated unit testing or test-driven development.

For any Entity class we will create repository class and interface, so when you instantiate object of repository class in controller, interface should be used so it can accept reference of any object that implements repository interface. When controller runs under web server, then it received a repository that can work with Entity Framework and when it runs under unit test then it receives repository that works with data that can be manipulated easily for testing.

Below example shows relationship between controller class and Database Context classes.

Image 1

Using the code

We can perform CRUD operation easily using entity framework in MVC. Using generic repository pattern it’s not required to write repetitive code for CRUD operation, using generic repository pattern we can achieve this functionality easily. One repository needs to be written which will be base for all further repositories and support below operations.

  1. ADD
  2. UPDATE
  3. DELETE
  4. GET (by filer criteria)
  5. GET ALL
C#
/// <summary>
/// Defines interface for common data access functionality for entity.
/// </summary>
/// <typeparam name="TType">Type of entity.</typeparam>
public interface IRepository<TType>
{
    TType Add(TType entity);

    bool Update(TType entity);

    bool Delete(TType entity);

    TType Get(Expression<Func<TType, bool>> filter);

    ICollection<TType> GetAll();
}

Above is a code snippet for IRepository which will be inherited to GenericReporitoty, and all these methods will be implemented in it. It is a common repository interface which will be inherited to all individual repository interfaces to support all generalized operations. Here, TType is a type of EntityObject which is going to be processed. We can filter database context as well using Expression. We need to pass Lamda expression of filter expression to apply filter on data source.
Ex. x=>x.Name == ”vijay”

C#
/// <summary>
/// Defines a class for generic entity repository to access common functionality for data access layer.
/// </summary>
/// <typeparam name="TType">Type of entity.</typeparam>
/// <typeparam name="TContext">Type of object context.</typeparam>
public abstract class GenericRepository<TType, TContext> : IRepository<TType>
    where TContext : ObjectContext, new()
    where TType : EntityObject
{
    private readonly TContext _entity = new TContext();

    protected TContext Context
    {
        get { return this._entity; }
    }

    protected string GetEntitySetName(string entityTypeName)
    {
        return this._entity.MetadataWorkspace
                            .GetEntityContainer(this._entity.DefaultContainerName, DataSpace.CSpace)
                            .BaseEntitySets
                            .Single(x => x.ElementType.Name.Equals(entityTypeName)).Name;
    }
 
    public TType Add(TType entity)
    {
        this._entity.AddObject(this.GetEntitySetName(typeof(TType).Name), entity);
        this._entity.SaveChanges();
        return entity;
    }

    public virtual bool Update(TType entity)
    {
        this._entity.AttachTo(this.GetEntitySetName(typeof(TType).Name), entity);
        this._entity.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
        this._entity.SaveChanges(SaveOptions.DetectChangesBeforeSave);
        return true;
    }

    public virtual bool Delete(TType entity)
    {
        this._entity.AttachTo(this.GetEntitySetName(typeof(TType).Name), entity);
        this._entity.ObjectStateManager.ChangeObjectState(entity, EntityState.Deleted);
        this._entity.SaveChanges();
        return true;
    }

    public TType Get(Expression<Func<TType, bool>> filter)
    {
        return this._entity.CreateObjectSet<TType>().SingleOrDefault(filter);
    }

    public ICollection<TType> GetAll()
    {
        return this._entity.CreateObjectSet<TType>().ToList();
    }
}

Above is a code snippet for final Generic Repository in which all the generic methods for above mentioned operations are implemented. This repository will support all the entities whose base class is EntityObject. (Added through Entity framework) I have used Ninject as IocContainer/Dependency injection, so instance of repository will be injected to controller automatically, also object of ObjectContext is exposed so that we can query Data store for other different scenarios as well.

Using dependency injection we can implement TDD approach effectively as when we run application on web server then we can reference repository interface to entity framework data context and when we want to test the application then we can reference repository interface to some mock (in-memory) data collection.

Dependency injection

Today there is a greater focus than ever on reusing existing components and wiring together disparate components to form a cohesive architecture. But this wiring can quickly become a daunting task because as application size and complexity increase, so do dependencies. One way to mitigate the proliferation of dependencies is by using Dependency Injection (DI), which allows you to inject objects into a class, rather than relying on the class to create the object itself.
The Inversion of Control (IoC) and Dependency Injection (DI) patterns are all about removing dependencies from your code.

Image 2

In above example Client Class has used reference of IService1 which is implemented by Service1 class. So Client class is not responsible or worried about object creation of Service1/IService1 it will be taken care/Injected by Builder application. So Client Class can rest assured that any time IService1 interface is referenced object will be available.

To use Ninject in web application (MVC) as IocContainer following things needs to be taken care.

  1. Add reference of
    • Ninject.dll
    • Ninject.Web.Common.dll
    • Ninject.Web.Mvc.dll
  2. Update Global.asax class and change base class to NinjectHttpApplication and override two methods
    • CreateKernel
      In this method object of IKernel needs to be created and return
      C#
      protected override IKernel CreateKernel()
              {
                  var kernel = new StandardKernel(new AppModule());
                  return kernel;
              }
      One class which is derived from NinjectModule needs to be created to give as a parameter in StandardKernel constructor.
      NinjectModule is responsible for defining mapping between interface and actual repository which will be used to inject repository instance into controller class.
    • OnApplicationStarted
C#
public sealed class UserRepository : GenericRepository<User, DataEntityContainer>, IUser
{
    public override bool Update(User entity)
    {
        entity.EntityKey = new EntityKey("DataEntityContainer.Users", "Id", entity.Id);
        return base.Update(entity);
    }

    public override bool Delete(User entity)
    {
        entity.EntityKey = new EntityKey("DataEntityContainer.Users", "Id", entity.Id);
        return base.Delete(entity);
    }

    public IQueryable<User> GetBySearch(Expression<Func<User, bool>> search)
    {
        return this.Context.Users.Where(search);
    }
}

If any more method needs implementation then those methods will be added to IUser and implemented in individual repository. This DataAccess layer reference is added to MVC web application and dependency injection is implemented using Ninject.

Also this article shows how to use data annotations for validation in MVC and how validation messages can be retrieved from resource files to achieve multilingual functionality.

C#
[Required(AllowEmptyStrings = false, ErrorMessageResourceName = "NameRequired", ErrorMessageResourceType = typeof(ErrorMessage))]
        [StringLength(25, ErrorMessageResourceName = "NameLength", ErrorMessageResourceType = typeof(ErrorMessage))]
        public string Name { get; set; }

Points of Interest

While updating entity in database as EntityKey and EntityState will be null so these values needs to be set before updating/deleting entity using EF. Also this generic repository pattern is created using database first approach.

License

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


Written By
Software Developer (Senior)
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThank you Pin
Bhagwant Singh14-Apr-15 20:01
Bhagwant Singh14-Apr-15 20:01 
QuestionGood Article Pin
mdshohelrana19-Jan-15 21:07
professionalmdshohelrana19-Jan-15 21:07 
GeneralMy vote of 1 Pin
jenish rabadiya11-Jan-15 18:08
jenish rabadiya11-Jan-15 18:08 
QuestionI stopped reading after... Pin
jcmcbeth8-Oct-13 12:24
jcmcbeth8-Oct-13 12:24 
GeneralMy vote of 1 Pin
jcmcbeth8-Oct-13 12:20
jcmcbeth8-Oct-13 12:20 
QuestionAnd where is the unit of work? Pin
huer122-Sep-13 8:12
huer122-Sep-13 8:12 
Nice article, good introduction, but I miss the unit of work. I have seen such a repository implementation recently in a project. The result was, that the application was slow because the DB has been accessed to often.
The SaveChanges method should be separate in a unit of work.

Regards, Roman
QuestionLoading data from a combination of referenced tables.. Pin
Pravin baskaran17-Aug-13 0:04
Pravin baskaran17-Aug-13 0:04 
AnswerRe: Loading data from a combination of referenced tables.. Pin
vijay__p19-Aug-13 21:02
professionalvijay__p19-Aug-13 21:02 
QuestionSophisticated work! Pin
Member 815195125-Jul-13 8:15
Member 815195125-Jul-13 8:15 
AnswerRe: Sophisticated work! Pin
vijay__p25-Jul-13 23:45
professionalvijay__p25-Jul-13 23:45 
GeneralMy vote of 1 Pin
Hazem Salem14-May-13 10:57
Hazem Salem14-May-13 10:57 
GeneralRe: My vote of 1 Pin
vijay__p16-May-13 19:30
professionalvijay__p16-May-13 19:30 
QuestionHow You Used Ninject then? Pin
Hazem Salem14-May-13 10:57
Hazem Salem14-May-13 10:57 
AnswerRe: How You Used Ninject then? Pin
vijay__p15-May-13 0:28
professionalvijay__p15-May-13 0:28 

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.