Click here to Skip to main content
15,867,141 members
Articles / Web Development / ASP.NET

Repository Pattern with Entity Framework using EntityTypeConfiguration

Rate me:
Please Sign up or sign in to vote.
4.72/5 (22 votes)
20 Mar 2013CPOL3 min read 130.9K   42.3K   68   20
Repository Pattern with Entity Framework using EntityTypeConfiguration

Introduction

I was looking for Repository Pattern with Entity Framework Code First with EntityTypeConfiguration, but I was unable to find such an integrated sample. Here, I am touching only the basics. It's my first article.

Background

I am taking plain two objects, Category and Product to make this article simple.

I am using EntityTypeConfiguration for making different layers to interact with database and field validation.

Following is the Solution tree.

**Note: We need to add Entity Framework reference in the EfRepPatTest.Data project.

Development Tools

  • VS 2010
  • Entity Framework Library

Using the Code

First of all, we shall create three projects in the solution, of them, two are class libraries and the other one is a console project for implementation.

Solution Name EfRepositoryPatterTest
Class Library Name EfRepPatTest.Entity
EfRepPatTest.Data
Console Application EfRepPatTest.Implementation

In the EfRepPatTest.Entity project, we shall create the following class:

BaseEntity.cs

C#
public class BaseEntity<T>
{
    public T Id { get; set; }
}

IRepository.cs [Interface]

That contains action of:

C#
public interface IRepository<TEntity> where TEntity:class 
{
    IQueryable<TEntity> GetAll();
    TEntity GetById(object id);
    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

Category.cs

It will inherit BaseEntity class for getting the Id property and assigning Id field as integer.

C#
public class Category:BaseEntity<int>
{
    public virtual string Name { get; set; }

    public List<Product> Products { get; set; }
}

Product.cs

Same as category class.

C#
public class Product:BaseEntity<long>
{
    public virtual int CategoryId { get; set; }
    public virtual Category Category { get; set; }
    public virtual string Name { get; set; }
    public virtual int MinimumStockLevel { get; set; }
}

EfRepPatTest.Data project holds the following classes or interfaces.

Add reference of EntityFramework and EfRepPatTest.Entity in this project.

First of all, create an interface that drives DbContext class means DataContext class will consume.

IDbContext.cs

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

Here, IDbSet interface belongs to System.Data.Entity namespace. Create a class named DataContext that will inherit DbContext and consume IDbContext.

DataContext.cs [Partial]

C#
public class DataContext: DbContext,IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }
}

Before discussing the DataContext class’s method, we need another two class that will map Entity with EntityTypeConfiguration and hold data validation logic of Database table.

Create folder name, Mapping and place the CategoryMap and ProductMap class in it [optional].

CategoryMap.cs

C#
public class CategoryMap:EntityTypeConfiguration<Category>
{
    public CategoryMap()
    {
        ToTable("Category");
        HasKey(c => c.Id).Property
              (c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(c => c.Name).IsRequired().HasMaxLength(50);
    }
}

ProductMap.cs

C#
public class ProductMap:EntityTypeConfiguration<Product>
{
    public ProductMap()
    {
        ToTable("Product");
        HasKey(p => p.Id).Property(p => p.Id).HasDatabaseGeneratedOption
              (DatabaseGeneratedOption.Identity);
        //CategoryId as foreign key
        HasRequired(p => p.Category)
            .WithMany(c=>c.Products)
            .HasForeignKey(p => p.CategoryId);
        Property(p => p.Name).IsRequired().HasMaxLength(100);
        Property(p => p.MinimumStockLevel);
    }
}

The above part will help us in avoiding direct use of Entities[Product and Category] as database table, instead it will cover db table logic, validation.

Now add "OnModelCreating" method in DataContext class for attaching the Entity as part of model. The following code snippet will demonstrate how to configure EntityTypeConfiguration driven class [ProductMap, CategoryMap] with ModelBuilder manually.

C#
{
    modelBuilder.Configurations.Add(new CategoryMap());
    modelBuilder.Configurations.Add(new ProductMap());
    base.OnModelCreating(modelBuilder);
}

Here, the problem is all of the classes need to be configured manually. That’s why I would like to avoid it. The following codes will help us to do it automatically.

DataContext.cs [Full]

C#
public class DataContext: DbContext,IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
        .Where(type => !String.IsNullOrEmpty(type.Namespace))
        .Where(type => type.BaseType != null && type.BaseType.IsGenericType && 
           type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
        foreach (var type in typesToRegister)
        {
            dynamic configurationInstance = Activator.CreateInstance(type);
            modelBuilder.Configurations.Add(configurationInstance);
        }

        base.OnModelCreating(modelBuilder);
    }
}

We haven’t implemented the IRepository interface yet, through RepositoryService class, we will implement it.

RepositoryService.cs

C#
public class RepositoryService<TEntity>:IRepository<TEntity> where TEntity:class 
{
    private IDbContext Context;

    private IDbSet<TEntity>  Entities
    {
        get { return this.Context.Set<TEntity>(); }
    }

    public RepositoryService(IDbContext context)
    {
        this.Context = context;

    }

    public IQueryable<TEntity> GetAll()
    {
        return Entities.AsQueryable();
    }

    public TEntity GetById(object id)
    {
        return Entities.Find(id);
    }

    public void Insert(TEntity entity)
    {
        Entities.Add(entity);
    }

    public void Update(TEntity entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");

        this.Context.SaveChanges();
    }

    public void Delete(TEntity entity)
    {
        Entities.Remove(entity);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (this.Context != null)
            {
                this.Context.Dispose();
                this.Context = null;
            }
        }
    }
}

The "private IDbSet<TEntity> Entities" property will return DbSet instance for access to entities of the given type in the context.

Now, you need a class for initializing the database. Add a class named DataBaseInitializer.

DataBaseInitializer.cs

C#
public class DataBaseInitializer : IDatabaseInitializer<DataContext>
{
    public void InitializeDatabase(DataContext context)
    {
        context.Database.CreateIfNotExists();
    }
}

Implementing the application through EfRepPatTest.Implementation console project:

The Program.cs class looks like the following:

C#
class Program
{
    static void Main(string[] args)
    {
        var context = new DataContext();
        var dataBaseInitializer = new DataBaseInitializer();
        dataBaseInitializer.InitializeDatabase(context);

        var categoryRepository = new RepositoryService<Category>(context);

        //Adding category in the category entity
        var category = new Category()
        {
            Name = "Baverage"
        };
        var products = new List<Product>();

        //Adding product in the product entity
        var product = new Product()
            {
                Name = "Soft Drink A",
                MinimumStockLevel = 50
            };
        products.Add(product);

        product = new Product()
        {
            Name = "Soft Drink B",
            MinimumStockLevel = 30
        };
        products.Add(product);

        category.Products = products;

        //Insert category and save changes
        categoryRepository.Insert(category);
        context.SaveChanges();

        ///////////////////////////////////////////////////////////////////////////////
        /////////////////For the next project we shall add Dependency Injection////////
        ////////////////But now we have add a Service layer for test manually//////////
        ///////////////////////////////////////////////////////////////////////////////
        IProductService productRepository = new ProductService();

        Console.WriteLine("\n");
        Console.WriteLine("Product List:");
        Console.WriteLine("-------------------------------------------------");
        foreach (var product1 in productRepository.GetAll())
        {
            Console.WriteLine(string.Format("Product Name : {0}",product1.Name));
            if (product1.Id == 9)
            {

                product1.Name = "Soft Drink AAA";
                productRepository.Update(product1);
            }
        }
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
}

Here, we have added "EfRepPatTest.Service" project to test the service. It will help us in the next article.

Connection string in App.config [highlighted portion]:

XML
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information
on Entity Framework configuration, visit
http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" 
             type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection,
EntityFramework, Version=4.4.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" 
             requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory,
EntityFramework" />
  </entityFramework>

  <connectionStrings>
      <add name="DataContext" 
         providerName="System.Data.SqlClient" 
         connectionString="Data
Source=YourSERVER;Initial Catalog=EfDBExistRepository;Integrated
Security=True;MultipleActiveResultSets=True;"/>
 
  </connectionStrings>
</configuration>

As name of connection string [name="DataContext"] is the same as DataContext.cs class, it will work automatically.

That may help!

Next Article

History

  • 20th March, 2013: Initial version

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)
Bangladesh Bangladesh
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 2 Pin
Eugene Griaznov5-Oct-13 18:53
Eugene Griaznov5-Oct-13 18:53 
QuestionHow to modify a database first? Pin
yourber29-Sep-13 15:11
yourber29-Sep-13 15:11 
GeneralMy vote of 2 Pin
StianSandberg7-Jun-13 0:36
StianSandberg7-Jun-13 0:36 
Questionthanks Pin
noor rahman3-Jun-13 19:55
noor rahman3-Jun-13 19:55 
Its really help me out thanks keep it up your good work
QuestionWork with WCF Pin
Yasithl8-May-13 3:25
Yasithl8-May-13 3:25 
AnswerRe: Work with WCF Pin
MdAsifBd17-May-13 20:14
MdAsifBd17-May-13 20:14 
GeneralRe: Work with WCF Pin
Yasithl20-May-13 0:53
Yasithl20-May-13 0:53 
SuggestionIDisposable Pin
Member 15540717-May-13 7:25
Member 15540717-May-13 7:25 
GeneralRe: IDisposable Pin
MdAsifBd7-Jun-13 9:08
MdAsifBd7-Jun-13 9:08 
QuestionMy vote of 2 Pin
Michael J. Eber26-Mar-13 6:36
Michael J. Eber26-Mar-13 6:36 
GeneralMy vote of 4 Pin
fredatcodeproject20-Mar-13 6:22
professionalfredatcodeproject20-Mar-13 6:22 
GeneralRe: My vote of 4 Pin
MdAsifBd20-Mar-13 6:28
MdAsifBd20-Mar-13 6:28 
GeneralMy vote of 5 Pin
yanborowski20-Mar-13 3:55
yanborowski20-Mar-13 3:55 
GeneralMy vote of 2 PinPopular
User 482203318-Mar-13 23:54
User 482203318-Mar-13 23:54 
GeneralRe: My vote of 2 Pin
phani krishna reddy v3-Dec-14 12:33
phani krishna reddy v3-Dec-14 12:33 
GeneralMy vote of 3 Pin
ZeroDotNet14-Mar-13 10:58
ZeroDotNet14-Mar-13 10:58 
GeneralRe: My vote of 3 Pin
J. Wijaya14-Mar-13 17:43
J. Wijaya14-Mar-13 17:43 
AnswerRe: My vote of 3 Pin
MdAsifBd15-Mar-13 0:31
MdAsifBd15-Mar-13 0:31 
GeneralMy vote of 5 Pin
A_Haider14-Mar-13 4:45
A_Haider14-Mar-13 4:45 
GeneralRe: My vote of 5 Pin
MdAsifBd14-Mar-13 4:50
MdAsifBd14-Mar-13 4:50 

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.