Click here to Skip to main content
Click here to Skip to main content

Generic repository pattern using EF with Dependency injection (Ninject)

, 14 May 2013
Rate this:
Please Sign up or sign in to vote.
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.

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
/// <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”

/// <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.

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
      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
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.

[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)

Share

About the Author

vijay__p
Software Developer (Senior)
India India
No Biography provided

Comments and Discussions

 
QuestionI stopped reading after... Pinmemberjcmcbeth8-Oct-13 12:24 
GeneralMy vote of 1 Pinmemberjcmcbeth8-Oct-13 12:20 
QuestionAnd where is the unit of work? Pinmemberhuer122-Sep-13 8:12 
QuestionLoading data from a combination of referenced tables.. PinmemberPravin baskaran17-Aug-13 0:04 
AnswerRe: Loading data from a combination of referenced tables.. Pinprofessionalvijay__p19-Aug-13 21:02 
QuestionSophisticated work! [modified] PinmemberMember 815195125-Jul-13 8:15 
AnswerRe: Sophisticated work! Pinprofessionalvijay__p25-Jul-13 23:45 
GeneralMy vote of 1 PinmemberHazem Salem14-May-13 10:57 
GeneralRe: My vote of 1 Pinprofessionalvijay__p16-May-13 19:30 
QuestionHow You Used Ninject then? PinmemberHazem Salem14-May-13 10:57 
AnswerRe: How You Used Ninject then? Pinprofessionalvijay__p15-May-13 0:28 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 15 May 2013
Article Copyright 2013 by vijay__p
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid