7

I currently been assigned to a asp mvc project using entity framework. This will be a Line of Business application. I want to develop this app using repository and unit of work pattern. I'm new to this pattern (and new to .net too) and i am having a problem in understanding the pattern and how to implement it.

I have read numerous articles and i think this is how my application should be

Entity Framework -> Repository -> Unit of Work -> Client (Asp MVC)

I attach some code from this article http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

using System;
using ContosoUniversity.Models;

namespace ContosoUniversity.DAL
{
    public class UnitOfWork : IDisposable
    {
        private SchoolContext context = new SchoolContext();
        private GenericRepository<Department> departmentRepository;
        private GenericRepository<Course> courseRepository;

        public GenericRepository<Department> DepartmentRepository
        {
            get
            {

                if (this.departmentRepository == null)
                {
                    this.departmentRepository = new GenericRepository<Department>(context);
                }
                return departmentRepository;
            }
        }

        public GenericRepository<Course> CourseRepository
        {
            get
            {

                if (this.courseRepository == null)
                {
                    this.courseRepository = new GenericRepository<Course>(context);
                }
                return courseRepository;
            }
        }

        public void Save()
        {
            context.SaveChanges();
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposed = true;
        }

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

Unit of Work will have repositories and will create DBContext upon creation

So controller will create Unit of Work upon creation. To Show data i will use this code

var department = UoW.departmentRepository.Find(1);
return View(department);

and when client click save button, i will run this code

UoW.departmentRepository.Update(department);
UoW.Save();

My question:

  1. What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.

  2. Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?

Is there a complete sample project for this kind of application?

EDIT

As Ant P adviced, i need to add another layer to put my business logic.

This is what i have come so far

Unit Of Work:

public class UnitOfWork : IDisposable
{
    private DBContext _context = new DBContext();

    public DBContext Context 
    {
      get 
      {
        return this._context;
      }
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

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

Business Logic:

public class SalesBusinessLogic : IDisposable
{
    private ICustomerRepository _customerRepo;
    private ISalesRepository _salesRepo;
    private UnitOfWork _uow;

    public SalesBusinessLogic(UnitOfWork uow)
    {
      this._uow = uow;
    }

    public ICustomerRepository CustomerRepo
    {
        get
        {

            if (this._customerRepo == null)
            {
                this._customerRepo = new CustomerRepository(this._uow);
            }
            return this._customerRepo;
        }
    }

    public ISalesRepository SalesRepo
    {
        get
        {

            if (this._salesRepo == null)
            {
                this._salesRepo = new SalesRepository(this._uow);
            }
            return this._salesRepo;
        }
    }

    public bool Validate(Sales sales)
    {
      //this is where validation performed
      return true;
    }
}

Controller:

public SalesController : Controller
{
    private UnitOfWork _uow = new UnitOfWork();
    private SalesBusinessLogic _bl = new SalesBusinessLogic(this._uow);

    public ActionResult Index()
    {
        var sales = _bl.SalesRepo.Find(1);
        sales.CustomerID = 1;
        if _bl.Validate(sales)
        {
          _bl.SalesRepo.Update(sales);
          _uow.Save();
        }
        return View(sales);
    }    
}

Here UnitOfWork act only as provider of dbcontext, which will be consumed by business logic and repository. Repository will be in BusinessLogic class.

Server side validation will be handled by BusinessLogic and client side validation will be handled by viewmodel in Web Layer.

My only concern is that dbcontext in UnitofWork is publicly accessible.

Am i in the right direction here?

Reynaldi
  • 1,125
  • 2
  • 19
  • 41
  • Just a note: in your `SalesBusinessLogic` class, you are inheriting form `IDisposable` but you haven't implemented the `Dispose` method. For your code above this would be: `public void Dispose() { _uow.Dispose(); }` – GFoley83 Nov 25 '13 at 00:02

1 Answers1

9

What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.

This isn't an issue - the controller is instantiated per request. It doesn't persist while the user views the page. It sounds like you're misunderstanding at what point the controller is instantiated. When you instantiate the UnitOfWork within the controller's constructor, the process flow goes like this:

  • The user issues a POST request (by clicking 'Save').
  • The request reaches the server and the controller is instantiated (thereby instantiating the unit of work).
  • The action method is called.
  • The unit of work is disposed.

Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?

Typically, your business logic would be abstracted into a separate layer that sits between your web application and your repositories. Tutorials that show you repositories injected directly into controllers assume that you have "thin" business logic.

However, validation definitely isn't the job of a repository. You should create a separate view model for each view and validate those in your controller. The repository should be used pretty much solely for CRUD operations.

Ant P
  • 24,820
  • 5
  • 68
  • 105
  • 1
    Good answer +1, And if you need to "validate entity which relate to other entity" then there is an example of how to use entity framework to validate against the database with a unit of work here: http://stackoverflow.com/a/16647237/150342 – Colin Sep 19 '13 at 08:38
  • @AntP thanks for explaining the lifecycle of controller. i'm new to .net and still have lots of learning. so i need to put business logic in another layer/dll. but as colin mentioned, what if the validation needs to access database/dbcontext? so business logic must have reference to entity framework. and how business logic looks like? does it have uow and repository inside the class? how should the controller call business logic? can you elaborate more? maybe put some sample code or direct me to an article or two? – Reynaldi Sep 19 '13 at 08:55
  • @colin thanks for the link. but where should i put the validation? is it in DAL or BLL? from the link, the validation perform in uow – Reynaldi Sep 19 '13 at 08:59
  • Oh boy ;-) That's a question I'm under qualified to answer. You've got client-side validation and server-side validation and sometimes you need to go to the database to do your validation. If you just need to check whether a field is unique then I think that fits perfectly well in the data layer. My link shows validation in the context class and how I feed that back to the ui (with "thin" business logic as Ant describes it). If you've got more complex business validation then it probably fits in the BLL. This is worth reading: http://msdn.microsoft.com/en-us/data/gg193959.aspx – Colin Sep 19 '13 at 09:22
  • @Reynaldi You're on the right track - I'd look at maybe introducing a service/BLL between your controller and giving your UnitOfWork to that instead. If the validation agains the DB is straightforward, however, there's nothing wrong with just doing it in your controllers - avoid unnecessary abstraction. – Ant P Sep 19 '13 at 09:53
  • this information is very helpful for others too. Thanks for sharing. – Anupam Singh Sep 23 '14 at 13:24
  • I don't think UnitOfWork going to be disposed automatically, and you should override default dispose method of Controller and after calling its base dispose method then call dispose method of UnitOfWork. – Jalali Shakib Oct 05 '15 at 06:35