ASP.NET MVC, EntityFramework, DBContext, Repository in a different Project

teh0wner picture teh0wner · Oct 28, 2013 · Viewed 12k times · Source

I am currently working on an ASP.NET MVC 5 project, and I am trying to polish the architecture of the project; make it as clean and easy for people to work on it in the future as possible.

For starters I have moved my EntityFramework models (including IdentityUser and AccountViewModel) to a Class library project within the same solution. This is referenced by the main MVC project at the moment.

However, I am now contemplating on creating a new Data Access Layer project which will hold the DbContext (or DbContexts, if I decide on using multiple DbContexts) as well as the data access layer. What is the best method to go on about doing this?

This DAL project will reference the Model project, and the main MVC project will only reference the DAL project.

After reading this article! I was wondering if indeed the repository pattern is indeed obsolete when using EntityFramework.

So my two main questions are:

1) Whats the best way to pull out DAL into a separate project

2) Whats the best way to access the database content using EF

Answer

Aage picture Aage · Oct 29, 2013

Your question is pretty broad. For instance, what do you mean by the "the best way to access the database content using EF"? The best way in terms of performance?

I will try to answer by giving an option I prefer (of which I mostly use some variant), which uses the repository pattern. If you'd use your EF sets directly as a repository you might argue you wouldn't need the repository pattern, but I like to wrap those in one of my own.

Since I can't know what you mean by the best way, I'll give my personal preference which would suite a typical web project.

I won't be posting all the code to make it completely functional, but you should get a clear idea of what's going on.

Setup (4 projects):

UI ----------> Domain.Logic (w. Domain.Models) -----------------> Data (Holding the EF Context).

Data:

public partial class EFContextContainer : DbContext 
enter code here
public EFContextContainer ()
        : base("name=EFContextContainer")
    {
    }

public DbSet<IdentityUser> IdentityUsers { get;set; } 

With a wrapper returning the context:

public static class Database
{
    public static EFContextContainerGetContext()
    {
        return new EFContextContainer();
    }

}

You could have a repository setup like this:

Interface:

public interface IRepository<T> where T : class
{
    IQueryable<T> GetAll();
    T GetById(Guid id);
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(Guid id);
}

Implementation (only implemented the Add(T entity) for the sake of brevity):

public class EFRepository<T> : IRepository<T>, IDisposable where T : class
{
    public EFRepository(DbContext dbContext)
    {
        if (dbContext == null)
            throw new ArgumentNullException("dbContext");
        DbContext = dbContext;
        DbSet = DbContext.Set<T>();

    }

    protected DbContext DbContext { get; set; }

    protected DbSet<T> DbSet { get; set; }

    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 void Dispose()
    {
        DbContext.Dispose();
    }

}

Domain:

Domain.Logic (IdentityUserManager would be a class in Domain.Models):

public class IdentityUserManager
{
    public void Add(IdentityUser idUser)
    {
        using(var idUserRepository = new EFRepository<IdentityUser>(Database.GetContext())
        {
            idUserRepository.Add(idUser);
        }
    }
}

UI:

[HttpPost]
public ActionResult Post(UserViewModel model)
{
    UserIdentity user = MapUser(model);
    var userManager = new IdentityUserManager();
    userManager.Add(user);

    return View(new UserViewModel());
}

(This isn't all composed in Visual Studio, so forgive any spelling errors.)

Admitting, there can be a lot more abstraction in this code, but it would be ridiculous to pen down an entire solution here. For instance, you could use the Unit of Work pattern as well, which works great with the repository pattern. So read this a an example, not a full guide on how to implement this setup. Things could be set up a lot cleaner than this example.

For an in-depth view of the implementation of some of these patterns, I urge you to take a look into the course Single Page Apps by John Papa on Plural Sight. He does an excellent job explaining the benefits of these patterns and how to implement them.