Creating an Application Using Entity Framework 4.1 Code First Approach

Posted by Akhil Mittal Articles | ASP.NET MVC August 03, 2012
This article puts some light on building a generic multilayered architecture using Entity Framework 4.1 and the MVC3 Razor view engine.
Reader Level:
Download Files:
 

Introduction

In my previous article I discussed developing a simple basic multilayered architecture for a .Net application. However there were a few points that I skipped since the article was for beginners. When we talk about an application architecture there are certain points that need to be clarified before proceeding; they are:

  • Is the architecture loosely coupled?
  • Is it to be service-based?
  • Where should the entities reside?
  • What should be the Mode of Communication with the database?
  • Does it require design patterns? If yes, What patterns should be implemented?
  • Should it be based on a Separation of Concerns?

To answer these types of questions, .Net 4 has come up with a generic solution, making use of the Entity Framework.

My effort in this article would be to put some light on building a generic multilayered architecture using Entity Framework 4.1 and the MVC3 Razor view engine. We'll use inversion of control to resolve dependency of layers. The points to be covered in this article would be as follows:

  • Use of Separation of Concerns,
  • Use of Code First approach,
  • POCO objects,
  • Repository Pattern,
  • Dependency Injection and Inversion of Control.

Architecture Overview

I have created an architecture to explain all these points, and we'll stick to this architecture throughout this article thus implementing a pragmatic understanding.

I have created a very simple application to add student details to a database. To edit it and to delete the data, my first page shows a list of all students added.

The architecture is service-based; the following are the components and pictorial representation (Figure1) of it. We'll discuss each of the following components in detail:

  1. CodeFirstData layer.
  2. CodeFirstEntities layer.
  3. CodeFirstServices layer.
  4. MVC Portal layer.

Figure1 

event1.gif

Architecture components

Let's discuss each and every component of the defined architecture in detail:

  1. CodeFirstData layer : The data layer is the class library defining a layer which is responsible for interacting with the database. It contains context classes and a factory pattern implementation to interact with the database. The layer contains the repository for each entity to map with the database, thus making a complete ORM (Object Resource Model) solution. The class library references the EntityFramework DLL to implement the dbcontext classes.
     
  2. CodeFirstEntities layer : The entity layer acts as a model for the MVC application, and is also responsible for the creation of the DataBase objects when the dbset is first executed. It contains Entity classes in POCO form, having relations and data annotations (Rules/Constraints to be specified for Database table/columns).

    The properties of the class results in a column name in the database and the name of the class in the Database table. The primary key is either defined by the property named Id or "Classname[Id]", in our case "StudentId"; this is the default protocol set by the Entity Framework to keep in mind when creating entities. Since this application is code first, we need to create the entities first.
     
  3. CodeFirstServices layer : The layer contains services that use repositories to fetch data from the database. The interaction between Services and Repositories is kept loosely coupled thus implementing Inversion of Control using Dependency Injection. Its constructor is based on dependency injection and does not allow the service to make a direct instance of our repositories. The service layer acts as an interface between controllers and repositories and passes controller requests to repositories.
     
  4. MVCPortal layer : MVCPortal layer is our UI layer; it contains Model/ViewModels, Views and Controllers. I am not going into details of MVC since its not our primary target. I assume you already know how to create and run a MVC application; let's have a quick review of MVC:

    1. Model / Viewmodel : Model classes are responsible for holding and manipulating data. We bind model/viewmodel classes to views to display model-specific data. Model classes are pre-populated by controllers to show data with the help of views.
       
    2. Views : Views hold together our UI templates. We have controller methods defined for every view, which populates the View Design with data, and requests a particular type of view to be rendered at the user's end as required.
       
    3. Controllers : Web-based MVC frameworks map URLs to server code in a slightly different fashion. Instead of mapping incoming URLs to html/aspx files, they instead map URLs to methods on classes. These classes are called "Controllers" and they are responsible for processing incoming HTTP requests, handling user input, retrieving and saving data, and determining the response to send back to the client (display HTML, download a file, redirect to a different URL, etc.).
      The layer makes use of Dependency injection to achieve Inversion of Control for services, thus not allowing controllers to directly access service instances. The IOC is achieved using the global.asax file using the UnityFramework library of Microsoft.
     
  5. DLLs : I have created a DLLs folder and given the output build path for every class library to that folder, for ease of access to DLLs for adding a reference. Now each DLL will be created in the DLLs folder and we can access the desired DLL from the same folder. Also keep the EntityFramework, UnityConfiguration DLLs into it.

    IOC and DI : Dependency Injection is an important component in my application . All the services are required to be late-bound with the Model layer with Dependency Injection. In addition, the IoC container manages the lifetime of service objects. For example the Context object. I set the lifetime type to PerThreadLifetimeManager in the Unity configuration. This makes one and only one context object created in a single request and the different request has a different context object. Another thing I want to mention is that ASP.NET MVC3 has its own way to provide Dependency Injection for a controller via implementing the DependencyResolver interface. The IoC container I used in the demo is Unity.

    Container : The "Container" or "IOC Container" is the main object that is used to create objects and inject dependencies into them. Whenever you want an object to be open to IoC, you have to use the container to create the instance using the container. The Resolve<T>() method instead of the "new" keyword.

    IService service = unityContainer.Resolve< Iservice>();

    I have added the following references to do that:

    Microsoft.Practices.Unity
    Microsoft.Practices.Unity.Configuration


    The code for IOC is implemented in the global.asax file.

The step-by-step process to create the application using EntityFramework Architecture follows.

Application Overview : We'll try to develop a simple studentDetails application by discussing the architecture. The application's main module will be to create a new student, edit an existing student, delete an existing student, and to show a list of all students. Looking into a wider/generic perspective, the application performs CRUD operations on the database with the help of the EF.

Note that we'll not create databases on our own; we just write classes and define the connection configuration of our database server in the web.config file and let the EntityFramework do the remainder of the job of creating the database, managing the database and mapping the database with our entities.

Step 1 : Creating a solution and blank projects/separating them logically/physically as layers

Our first initiative is to prepare our initial-level architecture, thereby creating a solution and adding project files to it. We create a solution named CodeFirstEntities and add three class libraries to it thus defining our three layers which are Entity, Data and Service. The names of the class libraries I chose are CodeFirstEntities, CodeFirstData and CodeFirstServices respectively.

Now add an MVC3 application to the solution called MvcPortal, that will act as a UI layer for our application. Refer to 
Figure 2 for implementing the first step.

(
Figure 2)

event2.gif

Step 2 : Creating Entities

Add the Student.cs class to the CodeFirstEntities project. This class will contain the student details, specific properties that will become the database table and columns. The class makes use of a DataAnnotation DLL to put data annotations (rules/constraints) over the properties that will be reflected in the database table. The constraints like max length and required parameters are provided as attributes over the properties of the class as shown in  Figure 3 and  Figure 4:

(
Figure 3)

event3.gif
(
Figure 4)

event4.gif

The above entities are very simple POCO (Plain Old CLR Object) classes and the entity Student is decorated with validation attributes in the System.ComponentModel.DataAnnotations namespace. Now we want to use these entities for defining model objects for the Entity Framework 4. Using the Code First approach of Entity Framework, we can first define the entities by simply writing POCO classes without any coupling with any API or database library. This approach lets you focus on the domain model which will enable Domain-Driven Development for applications. The EF Code First support is currently enabled with a separate API that runs on top of the Entity Framework 4.

Step 3 : Creating Repositories/Contexts

Our next step is to create the contexts/repositories for our application and classes that will interact with the database.

  1. Create Context Class for Entity Framework

    We have already prepared our domain model. Now let's create a class for working with the Entity Framework Code First. I have added a reference to the EntitFramework.dll CTP 4.1 to this class library project. We create two folders, DBInteractions and EntityRepositories, to segregate our classes as in Figure 5; we'll come to that later. First let me explain the context class to you.

    (Figure 5)

    event5.gif
    (Figure 6)

    event6.gif

    The above class CodeFirstContext in Figure 6 is derived from DbContext that can connect your model classes to a database. The CodeFirstContext class is mapping our Student class to the database table Student using DbSet<TEntity> where TEntity is any POCO class. When we run the application the first time, it will automatically create the database. The EF Code First looks for a connection string in the web.config or app.config that has the same name as the dbcontext class. If it does not find a connection string matching the convention, it will automatically create a database in the local SQL Express database by default and the name of the database will be the same name as the dbcontext class. You can also define the name of the database in the constructor of the dbcontext class. The model classes of the Code First work on the basis of conventions and we can also use a fluent API to refine our model. The convention for primary key is 'Id' or '<classname>Id' as I discussed before. If the primary key properties are detected with type 'int', 'long' or 'short', they will automatically be registered as identity columns in the database by default. Primary key detection is not case sensitive. We can define our model classes with validation attributes in the System.ComponentModel. DataAnnotations is a namespace and it automatically enforces validation rules when a model object is updated or saved.

    I ) DBInteractions
     
  2. Generic Repository for EntityFramework Code First

    We have now created a model class and a dbcontext class. Now we create a generic repository pattern for data persistence with EF Code First. Let's create a generic repository to work with DbContext and DbSet as follows. The following classes will be added to the DBInteractions folder for ease of understanding the logic.

    (Figure 7)

    event7.gif
     
  3. DataBase Factory

    We have our database factory class defined as follows:

    (Figure 8)

    event8.gif

    (Figure 9)

    event9.gif

    Where IDBFactory is the interface implemented by our factory class DBFactory. The factory class is inherited from the Disposable class as shown below in Figure 10, responsible for releasing and disposing database resources.

    (Figure 10)

    event10.gif
     
  4. RepositoryBase - The Generic Entity Repository base class

    event11.gif

    Above is the repository base class that contains all the methods to be implemented for CRUD DB operations. We can define more of our generic methods here, but for now, considering our application, these are enough for the proper understanding of how it works.
     
  5. Unit of Work

    The Unit of Work pattern maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems. We create a class for handling the Unit of Work pattern:

    Interface 

    event12.gif

    Class 

    event13.gif

    The Commit method is written in the UnitOfWork which will call the commit method of our Context class and it will execute the SaveChanges method of the DbContext class.

    II ) Repository

    In this article, we will be primarily focusing on the persistence against the Student entity. Let's create a repository for handling CRUD operations for Student
    using derive from a generic Repository EntityRepositoryBase<T>.

    Repository class for Student 

    Interface 

    event14.gif

    Class 

    event15.gif

Step 4 : Creating a Service layer

The Service Layer defines an application's scope and its available set of operations from the perspective of interfacing client layers. It encapsulates the application's business logic, controlling transactions and coordinating responses in the implementation of its operations. Controller classes should be made light and do not put much business logic onto it. We can use the service layer as the business logic layer and can encapsulate the rules of the application.

We define interfaces and the corresponding student service for our application business logic. Since we are targeting CRUD operations, so the methods are quite simple in implementation.

Interface

event16.gif

As we can see in the above interface the methods are to Get Student Details, List, Update and Delete Student.

Class 

using System.Collections.Generic;
using CodeFirstData.DBInteractions;
using CodeFirstData.EntityRepositories;
using CodeFirstEntities;

using CodeFirstServices.Interfaces; 
namespace CodeFirstServices.Services
{
    public class StudentService :
IStudentService
    {
        private readonly IStudentRepository _studentRepository;
        private readonly IUnitOfWork _unitOfWork;
        public StudentService(IStudentRepository studentRepository, IUnitOfWork unitOfWork)
        {
            this._studentRepository = studentRepository;
            this._unitOfWork = unitOfWork;
        } 
        #region IStudentService Members 
        public IEnumerable<Student> GetStudents()
        {
            var students = _studentRepository.GetAll();
            return students;
        } 
        public Student GetStudentById(int id)
        {
            var student = _studentRepository.GetById(id);
            return student;
        } 
        public void CreateStudent(Student student)
        {
            _studentRepository.Add(student);
            _unitOfWork.Commit();
        }
 
        public void DeleteStudent(int id)
        {
            var student = _studentRepository.GetById(id);
            _studentRepository.Delete(student);
            _unitOfWork.Commit();
        }
 
        public void UpdateStudent(Student student)
        {
            _studentRepository.Update(student);
            _unitOfWork.Commit();
        } 
        public void SaveStudent()
        {
            _unitOfWork.Commit();
        } 
        #endregion
    }
}


The class uses references of Repositories and Entities, and Dependency of Repositories is resolved in the Constructor of the service itself.

Step 5 : The MVC Portal

Before we start the MVC portal, let's clarify our logic for IOC and DI. I have already discussed IOC in the article. For resolving dependencies we create certain classes as discussed below, to get an independent service request. We also create a custom lifetime manager for Unity to store the container in the current ____

    public
class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable
    {
        public override object GetValue()
        {
            var assemblyQualifiedName = typeof (T).AssemblyQualifiedName;
            if (assemblyQualifiedName != null)
                return HttpContext.Current.Items[assemblyQualifiedName];
            return null;
        }
 
        public override void RemoveValue()
        {
            var assemblyQualifiedName = typeof (T).AssemblyQualifiedName;
            if (assemblyQualifiedName != null)
                HttpContext.Current.Items.Remove(assemblyQualifiedName);
        }
 
        public override void SetValue(object newValue)
        {
            var assemblyQualifiedName = typeof (T).AssemblyQualifiedName;
            if (assemblyQualifiedName != null)
                HttpContext.Current.Items[assemblyQualifiedName] = newValue;
        } 
        public void Dispose()
        {
            RemoveValue();
        }
    }
}

We create a dependency resolver for resolving service dependency as follows. ASP.NET MVC 3 has introduced a new interface IControllerActivator which lets you activate controllers with a custom behavior and can be used for dependency injection purposes. The IControllerActivator interface is discoverable using the dependency resolver. Let's create a custom controller activator class by deriving from the IControllerActivator intreface:

using System;
using System.Web.Mvc;
namespace CodeFirstPortal.IoC
{
    public class CustomControllerActivator :
IControllerActivator
    {       
        IController IControllerActivator.Create(
            System.Web.Routing.RequestContext requestContext,
            Type controllerType){
            return DependencyResolver.Current
                .GetService(controllerType) as IController;
        }     
    }
}

We also create a UnityController Factory and Configure contract and concrete types of unity in the global.asax file. ASP.NET MVC 3 has also introduced a new interface IDependencyResolver which exposes the two methods GetService and GetServices. The GetService method resolves singly registered services that support arbitrary object creation and the GetServices resolves multiply registered services. Implementations of the IDependencyResolver interface should delegate to the underlying dependency injection container to provide the registered service for the requested type. When there are no registered services of the requested type, the ASP.NET MVC framework expects implementations of this interface to return null from GetService and to return an empty collection from GetServices. Let's create a custom dependency resolver class by deriving from the IDependencyResolver interface to work with Unity to provide dependency injection.

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Practices.Unity; 

namespace CodeFirstPortal.IoC
{
    public class UnityControllerFactory :
DefaultControllerFactory
    {
        IUnityContainer container;
        public UnityControllerFactory(IUnityContainer container)
        {
            this.container = container;
        }
        protected override IController GetControllerInstance(RequestContext reqContext, Type controllerType)
        {
            IController controller;
            if (controllerType == null)
                throw new HttpException(
                        404, String.Format(
                            "The controller for '{0}' could not be found" + "or it does not implement IController.",
                        reqContext.HttpContext.Request.Path)); 
            if (!typeof(IController).IsAssignableFrom(controllerType))
                throw new ArgumentException(
                        string.Format(
                            "Requested type is not a controller: {0}",
                            controllerType.Name),
                            "controllerType");
           
try
            {
                controller= container.Resolve(controllerType) as IController;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(String.Format(
                                        "Error resolving the controller {0}",
                                        controllerType.Name), ex);
            }
            return controller;
        } 
    }

Resolving Service Dependency

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
 
namespace CodeFirstPortal.IoC
{
public class UnityDependencyResolver : IDependencyResolver
{       
    IUnityContainer container;      
    public UnityDependencyResolver(IUnityContainer container)
    {
        this.container = container;
    } 
    public object GetService(Type serviceType)
    {
       
try
        {
            return container.Resolve(serviceType);
        }
       
catch
        {               
            return null;
        }
    } 
    public IEnumerable<object> GetServices(Type serviceType)
    {
       
try
        {
            return container.ResolveAll(serviceType);
        }
       
catch
        {               
            return new List<object>();
        }
    }
}
}

global.asax

Add a service project reference, entity project reference and data project reference to the portal.

The SetResolver method of the DependencyResolver class provides a registration point for dependency injection containers. In this method, we configure the UnityDependencyResolver class for providing dependency injection with Unity 2.0. The SetResolver method will be working with any dependency injection container. If you want to use the StructureMap as the dependency injection container, you can create a dependency resolver class in order to work with the StructureMap by deriving from the IDependencyResolver intreface and later you can configure this class with the SetResolver method. The ASP.NET MVC 3 is providing a good support for working with dependency injection containers.

using System.Web.Mvc;
using System.Web.Routing;
using CodeFirstData.DBInteractions;
using CodeFirstData.EntityRepositories;
using CodeFirstPortal.IoC;
using CodeFirstServices.Interfaces;
using CodeFirstServices.Services;
using Microsoft.Practices.Unity;

namespace MvcPortal
{   
    public class MvcApplication : System.Web.
HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
 
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
            routes.MapRoute(
                "Default",
// Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
         }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas(); 
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
            IUnityContainer container = GetUnityContainer();
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        } 
        private IUnityContainer GetUnityContainer()
        {
           
//Create UnityContainer         
            IUnityContainer container = new UnityContainer()
            .RegisterType<IDBFactory, DBFactory>(new HttpContextLifetimeManager<IDBFactory>())
            .RegisterType<IUnitOfWork, UnitOfWork>(new HttpContextLifetimeManager<IUnitOfWork>())
            .RegisterType<IStudentService, StudentService>(new HttpContextLifetimeManager<IStudentService>())
            .RegisterType<IStudentRepository, StudentRepository>(new HttpContextLifetimeManager<IStudentRepository>());
            return container;
        }
    }
}


To start with MVC our first step is to define our connection string as follows in the web.config file:

event17.gif

Steps to Create Controllers and Views

  1. We start with a Home Controller, as it is the default controller set in global.asax to be called first:

    event18.gif

    When the Index action of the controller is called we redirect it to our Student Controller, which immediately returns a view to show a list of students if any exist. Since it's the first time we are creating the controller, it shows an empty list, the controller method of Student fetches a student list from the database, but first it creates the database, thus achieving our objective.
     
  2. We create a Student Controller. We define actions in the controller for each operation we want to perform as follows:

    using System;
    using System.Linq;
    using System.Web.Mvc;
    using CodeFirstEntities;
    using CodeFirstServices.Interfaces; 
    namespace CodeFirstPortal.Controllers
    {
        public class StudentController :
    Controller
        {
            private readonly IStudentService _studentService;
     
            public StudentController(IStudentService studentService)
            {
                this._studentService = studentService;
           } 

            public ActionResult Details(int? id)
            {
                var studentDetails = _studentService.GetStudentById((int) id);
                if (studentDetails == null) throw new ArgumentNullException("Not Found");
                return View(studentDetails);
            }
            public ActionResult Delete(int? id)
            {
                var studentDetails = _studentService.GetStudentById((int) id);
                if (studentDetails == null) throw new ArgumentNullException("Not Found");
                return View(studentDetails);
            } 
            [HttpPost]
            public ActionResult Delete(Student student)
            {
                _studentService.DeleteStudent(student.StudentId);
                return RedirectToAction("List", "Student");
            } 
            [HttpGet]
            public ActionResult Edit(int? id)
            {
                var studentDetails = _studentService.GetStudentById((int) id);
                if (studentDetails == null) throw new ArgumentNullException("Not Found");
                return View(studentDetails);
            }
     
            [HttpPost]
            public ActionResult Edit(Student student)
            {
                _studentService.UpdateStudent(student);
                return RedirectToAction("List", "Student");
            } 
            [HttpGet]
            public ActionResult Create()
            {
                return View();
     
            [HttpPost]
            public ActionResult Create(Student student)
            {
                var studentModel = new Student()
                                       {
                                           Address = student.Address,
                                           Country = student.Country,
                                           Name = student.Name,
                                           Age = student.Age,
                                           Email = student.Email
                                       };
                _studentService.CreateStudent(studentModel);
                return RedirectToAction("List", "Student");
            } 
            [HttpGet]
            public ActionResult List()
            {
                var students = _studentService.GetStudents();
                if (students.Any())
                {
                    return View("List", students);
                } 
                return View("List");
            }
        }
    }

    There are get and corresponding posts for each method responsible for data updates. The constructor of the controller initializes the service. We can see it does not create an instance directly.
     
  3. We create views for every action; it's easy if we right-click the controller action and create a view. It automatically creates a view with a Default folder named in the name of the constructor, so we can create all the views for our operations, and our solution looks like:

    event19.gif
     
  4. Now we are ready with our application to be executed, keep your fingers crossed and see the magic. I have used "_layout" as the master page to give some meaningful look and feel to my application; you can customize it. When you run the application by pressing F5, you will be redirected to the Index view of the Student Controller, which shows a list of students. Since we are running it the first time, we don't have an existing list and our application shows:

    event20.gif
     
  5. No wonder, just have a look at your DataBase (in my case I am using SQL Server 2008):

    event21.gif

    I got a Database created automativcally with the name CodeFirstApp having Student Table. Now you can cross-check the table with your entity, it's the same. So we have hit the target and our database is successfully created.
     
  6. Further Operations

    You can now test the application and perform further CRUD operations in the application and see the DataBase being updated.e.g. Create Student, as in:

    event22.gif

    After submitng by pressing Create, we get:

    event23.gif


    Therefore one student is created.

    We can edit the same student by pressing the edit link; we get the view:

    event24.gif

    Likewise we will see the details of the previously created student:

    event25.gif

    And deleting the student will redirect to:

    event26.gif

    I created 3 students in the same manner. You can create more and play with the application.

    event27.gif

Risk Factor : There is also a Risk Factor in implementing the EntityFramework. If we make a change to the entity, like deleting or changing a property, the context will drop and recreate the database, which may clearly lead to loss of your existing data. To avoid this critical situation, we add more code. We call the SetInitializer method of the DataBase class and set it to null in our dataBase Factory Class; see:

using System.Data.Entity
 
namespace CodeFirstData.DBInteractions
{
public class DBFactory : Disposable, IDBFactory
{
 
    public DBFactory()
    {
        Database.SetInitializer<CodeFirstContext>(null);
    }
    private CodeFirstContext dataContext;
    public CodeFirstContext Get()
    {
        return dataContext ?? (dataContext = new CodeFirstContext());
    }
    protected override void DisposeCore()
    {
        if (dataContext != null)
            dataContext.Dispose();
    }
}
}


The Database class is from the namespace System.Data.Entity, which provides the feature.

Conclusion

Here we used Inversion of control and Dependency Injection to Resolve Dependency between layers. We used the MVC 3 Razor view engine as our UI and integrated the layers to achieve our objective. The application was a description of simple CRUD operations on a Database. We learned how to use the Repository Pattern, Unit of Work pattern and Unity Framework. You can download the codebase and further enhance/extend it according to your need. Happy Coding.

You can follow my series on Learning MVC step by step mentioned below, moving from basics to advance level.The series covers LINQ to SQL, Entity Framework, Repository Pattern,UOW Pattern and similar modules step by step.

  1. Part 1: Introduction to MVC architecture and Separation of Concerns.
  2. Part 2: Creating MVC Application from scratch and connecting it with database using LINQ to SQL.
  3. Part 3: Connecting the MVC Application with the help of EntityFramework DB-First approach.
  4. Part 4: Connecting the MVC Application with the help of EntityFramework Code-First approach.
  5. Part 5: Implementing Repository Pattern in MVC Application with EntityFramework.
  6. Part 6: Implementing a generic Repository Pattern and Unit Of Work pattern in MVC Application with EntityFramework.





COMMENT USING

Trending up