Entity Framework: Seperating Entities from Data Layer

Desired seperation of layers when using Entity Framework

The 'ADO.NET Entity Framework' introduces many new features which were not available with 'LINQ to SQL'. One of the most important feature is it allows for 'Code First' approach. This approach has following characteristics:
  • Entities matching the domain model are created first and not the database.
  • DbContext is typcially handwritten and it can take care of creating/accessing database for us.
However, one important aspect is generally overlooked. What 'Code First' approach allows us to do is, it allows for using normal POCOs (Plain Old CLR Objects) as 'Entities'. An extension of this feature is that your 'Entities' and 'DBContext' can reside in different layers. This is extremely useful from reusability and unit-testability standpoint. In the below code notice that the Entities and DBContext lie in different namespaces (and projects, however the DBContext needs to have a reference to Entities project though).
namespace BusinessEntities
{   
    public partial class Student
    {
        public Student()
        {
            this.ContactInfoes = new HashSet<ContactInfo>();
        }
    
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Nullable<System.DateTime> DateOfBirth { get; set; }
    
        public virtual ICollection<ContactInfo> ContactInfoes { get; set; }
    }

    public partial class ContactInfo
    {
        public int Id { get; set; }
        public int StudentId { get; set; }
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public string Zip { get; set; }
        public string PhoneNumber { get; set; }
    
        public virtual Student Student { get; set; }
    }
}

    
namespace Data
{
    
    public partial class MyDBContext : DbContext
    {
        public MyDBContext() : base("MyDBContext") {     }
    
        public DbSet<ContactInfo> ContactInfoes { get; set; }
        public DbSet<Student> Students { get; set; }
    
        public virtual ObjectResult<GetStudent_Result> GetStudent(Nullable<int> id)
        {
            var idParameter = id.HasValue ?
                new ObjectParameter("id", id) :
                new ObjectParameter("id", typeof(int));
    
            return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<GetStudent_Result>("GetStudent", idParameter);
        }
    }
}
This has the following advantages:
  • Repository can only be present in 'Data Layer (or project)' and it only needs reference of layer containing 'Entities'
  • Entities become decoupled with Data Layer , they can be compiled as separate assembly and reused in any way you like.
  • If you feel like switching from Entity Framework to something else, you could still use your Entities.
  • Since 'Data Layer' is cleanly decoupled, you can mock it easily.

Can the seperation between Data Layer-Entities be achieved in 'Database First' approach?

For many types of projects it would make sense to use 'Database First' approach. The problem is, by default all the code (POCOs + DBContext) gets generated in same project/namespaces as the *.edmx file. I couldn't find an easy way to fix this. Luckily, I came across this EntityFramework Reverse POCO Generator extension. Once you install this, it creates *.tt files for every *.edmx you create. One of the *.tt file creates all entity classes for you while another creates 'DBContext'. You can modify the *.tt files to fix namespaces or simply copy the generate *.cs files to desired projects and change namespaces. I find this particular extension very useful.

Things to remember !

If you are not familiar with using 'Attach' method in EntityFramework ( 'DBContext.MyEntities.Attach(myObject)'), you may find yourself using it more frequently. This is because except DataLayer, all other layers view your entities as POCOs. You can only instantiate these classes with 'new' keyword, fill in values and send those to repository/data layer.


Copyright (c) 2007-2017 Ashish Patil . Please read FAQ for more details.

comments powered by Disqus