Click here to Skip to main content
15,884,177 members
Articles / Web Development / ASP.NET
Article

Models (POCO), Entity Framework and Data Patterns.

Rate me:
Please Sign up or sign in to vote.
4.74/5 (66 votes)
4 Jul 2013CPOL9 min read 238K   6K   168   32
Models (POCO), Entity Framework and Data Patterns

Introduction

In this application, I will explain how we can build our Models and Data layer using Microsoft best practices.

Our road map is to:

  1. Create Models POCO
  2. Create DBContext from Entity Framework
  3. Create Repositories (Pattern)
  4. Create UOW (Unit Of Work pattern)
  • POCO Models will act as data carriers and they are independent (stand alone). These classes don't know anything about the DB.
  • Entity framework is an ORM (object-relational mapper) that enables us to connect to the DB (SQL server) and map DB to our models and vice versa. We can consider it as a conduit.
  • Repository pattern will expose the data retrieval, updating and saving of the data to our DB by communicating with EF (Entity Framework), and to simplify and standardize the way we work with retrieval, updating and saving.
  • Unit of work pattern is to add all our repositories in one place, so we can do commit and unroll multiple changes to our repositories.

But why do we want to use all those patterns technologies? Well, the simple answer is reusability and maintainability, by decoupling the classes from their behaviour and following the single responsibility principle.

Image 1

Figure 1

Using the Code

Create Models POCO

We will start with models, easy and simple.

First, we will add new class library project into our solution called Model as shown in (Figure 2).

Image 2

Figure 2

Models are the data carriers like we said and illustrated in (Figure 1), those Models will be classes, simple classes only contain properties, no attributes describing infrastructure concerns or other responsibilities that your domain objects shouldn't have (independent) and we call them POCO. They are Plain Old CLR Objects (POCO) .

For our application, we will create three classes (Applicant, Certification, Skill) and add those classes to the Model Project that we have created.

Let's take a look at those classes:

C#
 public class Applicant
    {    
        public Applicant()
        {
            //because when we want to create a new applicant 
            //we have to initilize the collections
            //so we can add items into them.
            Certifications = new List<Certification>();
            Skills = new List<Skill>();        
        }
       
        [Key]
        public int ApplicantID { get; set; }
        public string First_Name { get; set; }
        public string Last_Name { get; set; }
        public string Email { get; set; }
        public string Tel_No { get; set; }
        public string Mobile_No { get; set; }
        public string Visa_Type { get; set; }
        public string LinkedIn_URL { get; set; }
        public string Objective { get; set; }
        public byte Active { get; set; }
        public virtual ICollection<Certification> Certifications { get; set; }
        public virtual ICollection<Skill> Skills { get; set; }
    }
 
public class Certification
    {
        [Key]
        public int id { get; set; }
        public string Title { get; set; }
        public string Name { get; set; }
        public Nullable<System.DateTime> Expire_Date { get; set; }
        public string Description { get; set; }
        public int ApplicantID { get; set; }
        public byte Active { get; set; }
        public virtual Applicant Applicant { get; set; }
    }
public class Skill
    {
        [Key]
        public int id { get; set; }
        public string Description { get; set; }
        public int ApplicantID { get; set; }
        public byte Active { get; set; }
        public virtual Applicant Applicant { get; set; } 
    }

Those are just simple classes, but if you notice, you will see that we have key attribute, which comes from (using System.ComponentModel.DataAnnotations;). It's just to indicate that the id is the primary key for the entity framework, but the entity framework is smart enough to know that property with id name is the primary key without adding the [key] attribute.

Create DBContext from Entity Framework

First, we will add new class library project into our solution called Data as shown in (Figure 3).

Image 3

Figure 3

Second, we will add a reference to Model Project, as shown in (Figure 4).

Image 4

Figure 4

Finally, we will add entity framework from Manage NuGet packages, we can go to the Data Project in solution explorer, right click and choose Manage NuGet Packages as shown in (Figure 5).

Image 5 

Figure 5

Then, search for entity framework in the search box and choose entity framework from Microsoft and click install, as shown in (Figure 6).

Image 6

Figure 6

Now, we can start to build our DbContext class.

DbContext comes from Entity framework which allows us to interact between our database and our Models. It basically defines the relations between Models and the DB, personally I call the DbContext the conduit.

In the Dbcontext, we will have DbSet<T> which defines the relation between Tables and Models. When we go to our example, the DbContext will contain public DbSet<Applicant> Applicants { get; set; }, consider DbSet as the glue that will tie our models with table in DB.

Another thing we will have inside our DbContext is Configurations, which is responsible for configuring Entity(Tables) relations in DB.

Here is the DbContext class:

C#
public partial class MyExperienceDBContext : DbContext
    { 
        public MyInfoDBContext()
            : base("Name=MyExperience")//this is the connection string name
        {
        }
 
        public DbSet<Applicant> Applicants { get; set; }
        public DbSet<Certification> Certifications { get; set; }     
        public DbSet<Skill> Skills { get; set; }      
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new ApplicantConfig());
            modelBuilder.Configurations.Add(new CertificationConfig());
       
            modelBuilder.Configurations.Add(new SkillConfig());          
        }
    }

I called the my DbContext class MyExperienceDBContext and this class inherits from DbContext which is part of the entity framework, in the constructor, I called the DbContext class constructor and passed the connection string name ("Name=MyExperience"), this connection string will exist of course inside the configuration file in your application.

As you can see from the OnModelCreating method, we are pointing to ApplicantConfig, CertificationConfig and SkillConfig classes which we will create, and please note that those classes normally contain the relations configuration and Column to model property .

Here are the configuration classes:

C#
  public class SkillConfig : EntityTypeConfiguration<Skill>
    {
        public SkillConfig()
        {            
            // Relationships.
            //skill has relation with applicant.
            //applicant has many skills (one applicant has many skills )
            //forign key on skill is ApplicantID
            this.HasRequired(t => t.Applicant)
                .WithMany(g => g.Skills)
                .HasForeignKey(d => d.ApplicantID); 
        }
    } 
 
public class CertificationConfig : EntityTypeConfiguration<Certification>
    {
        public CertificationConfig()
        {           
            // Relationships
            //Certification has relation with applicant.
            //applicant has many Certification (one applicant has many Certification )
            //forign key on Certification is ApplicantID
            this.HasRequired(t => t.Applicant)
                .WithMany(t => t.Certifications)
                .HasForeignKey(d => d.ApplicantID); 
        }
    } 
 
public class ApplicantConfig : EntityTypeConfiguration<Applicant>
    {
        public ApplicantConfig()
        {
            
        }
    }

Notice that the configuration classes inherit from EntityTypeConfiguration<T> which comes from (using System.Data.Entity.ModelConfiguration;), this belongs to entity framework and it's responsible for the configuration of entities (tables) in DB.

Create Repositories (Pattern) (Inside Data Class Library Project)

Why Repository?

  • One place to retrieve update the data, hence maintainability.
  • Let's say you want to update applicant in your DB by talking to the DBContext directly, you can do that but you will have to write the same code each time you want to update but in different places, Repository will make sure that you never repeat your code (update in our example) again, hence reusability.
  • Following the single responsibility principle (SRP), by making sure that one place is responsible for retrieving or updating your DB.

Let's see how our repository will look like:

C#
public interface IRepository<T> where T : class
    {
        IQueryable<T> GetAll(); 
        T GetById(int id); 
        void Add(T entity);
        void Update(T entity);
        void Delete(T entity);
        void Delete(int id);
    } 
 
    /// <summary>
    /// The EF-dependent, generic repository for data access
    /// </summary>
    /// <typeparam name="T">Type of entity for this Repository.</typeparam>
    public class MyRepository<T> : IRepository<T> where T : class
    {
        public MyRepository(DbContext dbContext)
        {
            if (dbContext == null) 
                throw new ArgumentNullException("Null DbContext");
            DbContext = dbContext;
            DbSet = DbContext.Set<T>();
        }
 
        protected DbContext DbContext { get; set; }
 
        protected DbSet<T> DbSet { get; set; }
 
        public virtual IQueryable<T> GetAll()
        {
            return DbSet;
        }
 
        public virtual T GetById(int id)
        {           
            return DbSet.Find(id);
        }
 
        public virtual void Add(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
            if (dbEntityEntry.State != EntityState.Detached)
            {
                dbEntityEntry.State = EntityState.Added;
            }
            else
            {
                DbSet.Add(entity);
            }
        }
 
        public virtual void Update(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
            if (dbEntityEntry.State == EntityState.Detached)
            {
                DbSet.Attach(entity);
            }  
            dbEntityEntry.State = EntityState.Modified;
        }
 
        public virtual void Delete(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
            if (dbEntityEntry.State != EntityState.Deleted)
            {
                dbEntityEntry.State = EntityState.Deleted;
            }
            else
            {
                DbSet.Attach(entity);
                DbSet.Remove(entity);
            }
        }
 
        public virtual void Delete(int id)
        {
            var entity = GetById(id);
            if (entity == null) return; // not found; assume already deleted.
            Delete(entity);
        }
    }

Before we dive in, we should know why I choose generic Repository class, why not concrete class like MyApplicantRepository or MySkillRepository? Well, you can and it will still be Repository Pattern, but when you think about it, you will have to build a repository class for each Entity you have. In our example, we will end up writing 3 repositories. In normal projects, you will have 30 may be more, that means you will have to write new 30 repositories and that is not easy to maintain.

But when we use our Generic Repository, you can use it for all our Entities, easy to maintain and reuse.

First thing, we want to associate our repository to our Dbcontext. That will be done in the repository constructor:

C#
public MyRepository(MyExperienceDBContext dbContext)
        {
            if (dbContext == null) 
                throw new ArgumentNullException("Null DbContext");
            DbContext = dbContext;
            DbSet = DbContext.Set<T>();
        }

Because DbContext is not of specific type, we will set that in this line:

( DbSet =DbContext.Set<T>();) inside the repository constructor, the DbSet will be the same type as of our generic class <T>

In the interface IRepository, we have the following methods which MyRepository will have to implement:

C#
IQueryable<T> GetAll(); // we can build on top of it to get more filtered data
T GetById(int id); //get by ID
void Add(T entity);//add new
void Update(T entity);//update
void Delete(T entity);//delete entity
void Delete(int id);//delete by id

In MyRepository class, we are implementing IRepository methods. You can have a look at how we implement those methods, also you can modify them or add new of your own.

C#
public virtual void Update(T entity)
{
    DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
    if (dbEntityEntry.State == EntityState.Detached)
    {
        DbSet.Attach(entity);
    }  
    dbEntityEntry.State = EntityState.Modified;
}

For example, in the update method above, we check if the entity state is attached (DbContext knows about it) or not, if attached that means we can track the modifications, if not attached we have to attach it to our DbContext so we can track the new modification. Finally, we will change its status to modified to alert SaveChanges that we have changed entity.

You can go and check this link for more information about the states of the DbContext entities.

Now, let's start customizing our Repository class. I will assume that we want to get all applicants with specific skill, but we don't have this method in our Standard repository class!!! And also, this method is only meant for applicants entity (not applicable for Skills or Certifications entities) so what are we going to do???

Simple, we will create customize repository for applicant and at the same time, we will reuse the main repository, how??

Here, I started by creating IRepoApplicant which will inherit from IRepository<Applicant> as shown below:

C#
public interface IRepoApplicant:IRepository<Applicant>
    {      
        //new customize method for applicants
        //gets applicants with specific skill
        IQueryable<Applicant> GetApplicantsWihSkillName(string SkillName); 
    }

Here, you can see that I have created method GetApplicantsWihSkillName (string SkillName);, let's take a look at the implementation:

C#
public  class RepoApplicant :MyRepository<Applicant> ,IRepoApplicant  
    { 
      public RepoApplicant(DbContext context):base(context) 
      {
      
      } 
 
      //new customize method for applicants
      //gets applicants with specific skill
        public IQueryable<Applicant> GetApplicantsWihSkillName(string SkillName)
        {
            return GetAll().Where(p => p.Skills.Any
            (o => o.Description.ToLower() == SkillName.ToLower() ));
        }
    }

First, as you can see, we inherit from MyRepository<Applicant>, we know that this is for applicant Entity, hence the Applicant generic we pass to MyRepository.

Second, notice that the constructor will pass its DbContext to MyRepository.

Now, we can reuse everything from main repository and our new customized Repository for applicants.

Create UOW (Unit Of Work pattern) (Inside Data Class Library Project)

UOW is the final peace of our application.

Why We Use UOW?

UOW acts like a facade that will aggregate all our repositories initiation, calls and disposal in one place, and also separates (decouples) our application (Consol, Controllers, ASP.NET Web Page) from DbContext and repositories.

UOW will also take care of saving all our changes from multiple repositories in one place that we will create called commit method.

Let's see how the UOW will look like: 

C#
/// <summary>
 /// Interface for the My Experience Unit of Work"
 /// </summary>
 public interface IMyExperienceUow
 {
     // Save pending changes to the data store.
     void Commit();

     // Repositories
     IRepository<Skill> Skills { get; }
     IRepository<Certification> Certifications { get; }
     IRepoApplicant Applicants { get; }
 }

As you can see, its simple interface will expose our repositories and the commit method.

C#
/// <summary>
  /// The "Unit of Work"
  ///     1) decouples the repos from the console,controllers,ASP.NET pages....
  ///     2) decouples the DbContext and EF from the controllers
  ///     3) manages the UoW
  /// </summary>
  /// <remarks>
  /// This class implements the "Unit of Work" pattern in which
  /// the "UoW" serves as a facade for querying and saving to the database.
  /// Querying is delegated to "repositories".
  /// Each repository serves as a container dedicated to a particular
  /// root entity type such as a applicant.
  /// A repository typically exposes "Get" methods for querying and
  /// will offer add, update, and delete methods if those features are supported.
  /// The repositories rely on their parent UoW to provide the interface to the
  /// data .
  /// </remarks>
  public class MyExperienceUow : IMyExperienceUow, IDisposable
  {
      private MyExperienceDBContext DbContext { get; set; }

      public MyExperienceUow()
      {
          CreateDbContext();
      }

      //repositories
      #region Repositries
      private IRepository<Skill> _skills;
      private IRepository<Certification> _certifications;
      private IRepoApplicant _applicants;

      //get Skills repo
      public IRepository<Skill> Skills
      {
          get
          {
              if (_skills == null)
              {
                  _skills = new MyRepository<Skill>(DbContext);

              }
              return _skills;
          }
      }

      //get Certification repo
      public IRepository<Certification> Certifications
      {
          get
          {
              if (_certifications == null)
              {
                  _certifications = new MyRepository<Certification>(DbContext);

              }
              return _certifications;
          }
      }
      //get aplicants repo
      public IRepoApplicant Applicants
      {
          get
          {
              if (_applicants == null)
              {
                  _applicants = new RepoApplicant(DbContext);

              }

              return _applicants;
          }
      }

      #endregion

      /// <summary>
      /// Save pending changes to the database
      /// </summary>
      public void Commit()
      {
          DbContext.SaveChanges();
      }

      protected void CreateDbContext()
      {
          DbContext = new MyExperienceDBContext();

          // Do NOT enable proxied entities, else serialization fails.
          //if false it will not get the associated certification and skills when we
         //get the applicants
          DbContext.Configuration.ProxyCreationEnabled = false;

          // Load navigation properties explicitly (avoid serialization trouble)
         DbContext.Configuration.LazyLoadingEnabled = false;

          // Because Web API will perform validation, we don't need/want EF to do so
          DbContext.Configuration.ValidateOnSaveEnabled = false;

          //DbContext.Configuration.AutoDetectChangesEnabled = false;
          // We won't use this performance tweak because we don't need
          // the extra performance and, when autodetect is false,
          // we'd have to be careful. We're not being that careful.
      }

      #region IDisposable

      public void Dispose()
      {
          Dispose(true);
          GC.SuppressFinalize(this);
      }

      protected virtual void Dispose(bool disposing)
      {
          if (disposing)
          {
              if (DbContext != null)
              {
                  DbContext.Dispose();
              }
          }
      }

      #endregion
  }

Notice in the constructor, we call method CreateDbContext() which will take care of two things:

  • Initiating the DbContext ( DbContext = new MyExperienceDBContext();)
  • Configuring Our DbContext, for example you can set the lazyloading to false.

Please note that those configurations will be applied to all repositories.

Finally, we get repository as property, this property will take care of initiating the specific repository if not initiated.

C#
//get aplicants repo
        public IRepoApplicant Applicants
        {
            get
            {
                if (_applicants == null)
                {
                    _applicants = new RepoApplicant(DbContext); 
                }
 
                return _applicants; 
            }
        }

Now we are almost ready to lunch this monster application :), but first, we have to check our console application (maybe your application is MVC or ASP.NET but I'm using console) for a couple of small things:

  1. We will make sure that we have Connection string named ("MyExperience ") in our config file (App.config) inside of our console project, and it points to a new DB (No Tables).

    You can change the name of the connection string to whatever you like, but make sure to change it also inside the MyExperienceDBContext constructor, as shown below:

    C#
    public partial class MyExperienceDBContext : DbContext
        {     
            public MyInfoDBContext()
                : base("Name=MyExperience")//this is the connection string name
            {
            }
  2. Add Entity Framework to our console Project from NuGet, the same way we did add entity to Data Project. check (Figure 5).
  3. Add references in our console Project to Model and Data Projects , as shown in (Figure 7).

    Image 7

    Figure 7
  4. Add the code to your console application inside the main.
    C#
    //create new Certification
    var newCertification = new Certification();
    newCertification.Active = 1;
    newCertification.Description = "MCP";
    newCertification.Expire_Date = null;
    newCertification.id = 1;
    newCertification.Name = "Microsoft Profissional";
    newCertification.Title = "Microsoft Web Development ASP.NET";
    
    //create new skill
    var newSkill1 = new Skill();
    newSkill1.Active = 1;
    newSkill1.Description = "C#";
    newSkill1.id = 1;
    
    var newSkill2 = new Skill();
    newSkill2.Active = 1;
    newSkill2.Description = "MVC";
    newSkill2.id = 1;
    
    //create new applicant
    var newApplicant = new Applicant();
    
    newApplicant.Active = 1;
    newApplicant.ApplicantID = 1;
    newApplicant.Certifications.Add(newCertification);
    newApplicant.Email = "master_khalil@yahoo.com";
    newApplicant.First_Name = "Khaleel";
    newApplicant.Last_Name = "Esbaitah";
    newApplicant.LinkedIn_URL = "http://www.linkedin.com/pub/khaleel-esbaitah/1b/703/913";
    newApplicant.Mobile_No = "34234234";
    newApplicant.Objective = "To Join an organisation where I can emphasise my strength ";
    newApplicant.Skills.Add(newSkill1);
    newApplicant.Skills.Add(newSkill2);
    newApplicant.Tel_No = "1234567";
    newApplicant.Visa_Type = "PR"; 
    
    //add new applicant to applicants entity
    //using UOW facade
    IMyExperienceUow uow = new MyExperienceUow();
    
    uow.Applicants.Add(newApplicant);
    // commit all changes to DB
    uow.Commit(); 
    
    var result= uow.Applicants.GetAll();

We created new Skill, Certification and Applicant.

Notice that we did not initiate repository or DbContext, we just initiated New instance of our MyExperienceUow and then added our newly created applicant to Applicants repository that already exists inside our UOW class, then we committed the changes using Commit method.

Please note that we will not have any table inside our DB, but when we start our application and we add new Applicant then Commit, the Entity framework is smart enough to notice there are no tables, so it will create the tables from our DbContext and read our configurations.

Now, it's ready.

Important Note

In real life projects, 90% of the time the DB already exists, so what are we going to do??

Simple, there is a tool called "Entity Framework Power Tools". This basically will reverse engineer your DB to POCO Classes and DbContextClass. For more information, go to this link.

License

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


Written By
Software Developer
Australia Australia
.NET Web Developer from Sydney .
Passionate about Technologies.
Likes Video games.

Comments and Discussions

 
QuestionCan you please explain why does you use detached in your code what does it means Pin
Member 129444542-May-17 20:58
Member 129444542-May-17 20:58 
QuestionValidation in your simple classes Pin
Terppe5-Mar-17 23:49
Terppe5-Mar-17 23:49 
QuestionProblem in SQL Server 2012 with Demo Code Pin
jamuro775-Dec-16 4:02
jamuro775-Dec-16 4:02 
QuestionThanks Pin
rajen shrestha17-Apr-15 23:39
rajen shrestha17-Apr-15 23:39 
QuestionCan't understand one point Pin
Cebiyev4-Apr-15 5:54
Cebiyev4-Apr-15 5:54 
GeneralMy vote of 5 Pin
Cebiyev24-Mar-15 3:10
Cebiyev24-Mar-15 3:10 
QuestionThanks and Question Pin
Uthman Rahimi21-Jan-15 7:16
professionalUthman Rahimi21-Jan-15 7:16 
QuestionUnit Test Class Pin
Ming Fei Lam (Avery)21-Nov-14 2:30
Ming Fei Lam (Avery)21-Nov-14 2:30 
GeneralMy vote of 1 Pin
Aurimas15-Nov-14 4:18
Aurimas15-Nov-14 4:18 
QuestionHow can use a store procedure in this pattern Pin
Member 26960231-Oct-14 1:17
Member 26960231-Oct-14 1:17 
SuggestionGood article for beginners Pin
CoderPanda28-May-14 0:48
professionalCoderPanda28-May-14 0:48 
QuestionValidation Pin
wluijk3-Apr-14 7:33
professionalwluijk3-Apr-14 7:33 
QuestionExcellent Pin
a0110110112-Apr-14 7:30
a0110110112-Apr-14 7:30 
GeneralMy vote of 1 Pin
Antonio Ripa4-Jan-14 5:10
professionalAntonio Ripa4-Jan-14 5:10 
QuestionNeed help in Automapper implementation Pin
CodeChecker 56898-Aug-13 2:30
CodeChecker 56898-Aug-13 2:30 
QuestionNice article. Is the "Unit of Work" pattern implementation correct? Pin
John-ph7-Aug-13 16:27
John-ph7-Aug-13 16:27 
GeneralMy vote of 5 Pin
Monjurul Habib17-Jul-13 7:47
professionalMonjurul Habib17-Jul-13 7:47 
QuestionMany more repositories - 1 uow Pin
wiredeye15-Jul-13 7:05
wiredeye15-Jul-13 7:05 
GeneralMy vote of 4 Pin
Fabio Franco10-Jul-13 1:52
professionalFabio Franco10-Jul-13 1:52 
GeneralMy vote of 5 Pin
marcoingegneri9-Jul-13 22:27
professionalmarcoingegneri9-Jul-13 22:27 
GeneralMy vote of 2 Pin
demius9-Jul-13 18:49
demius9-Jul-13 18:49 
GeneralRe: My vote of 2 Pin
Member 852840918-Aug-13 4:27
Member 852840918-Aug-13 4:27 
GeneralRe: My vote of 2 Pin
raj_shaker18-Aug-13 23:40
raj_shaker18-Aug-13 23:40 
No it's not.

One cannot rename a facade and call it a unit of work. That's not how
design patterns like these work.
raj_shaker

GeneralMy vote of 5 Pin
Jeremy Hutchinson9-Jul-13 14:27
professionalJeremy Hutchinson9-Jul-13 14:27 
SuggestionYou may also be interested in "EntityFramework Reverse POCO Generator" Pin
Simon Hughes8-Jul-13 1:08
Simon Hughes8-Jul-13 1:08 

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.