Saturday, August 21, 2010

Code-First Entity Framework ISession for Tekpub MVC Starter Site

I've been using a lot of the ideas/code in Tekpub's MVC Starter Site for a personal project of mine. For better or worse the features of .NET 4.0 and MVC keep rapidly changing. I wanted to use both MVC 3 Preview 1 and Code-First Development with Entity Framework 4 so I've taken the time to upgrade the MVC Starter Site to support both of these features. You can download my working project here. See this post for more info on the headache to upgrade to MVC 3.

IMO it took way too much time to do this but a lot of it is probably due to my inexperience with MVC and in particular Dependency Injection.

Below is the class I added in order to use Code-First in the MVC Starter Site. The class inherits ISession. At first I tried to get access to the underlying ObjectContext so I could just use the already written EFSession class. I couldn't get this to work and then luckily I took a step back and realized I didn't need it to. I still haven't figure out how to do a working IReadOnlySession.cs but for my needs it won't be an issue at this time.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Data.Metadata.Edm;
using System.Data.Entity;

namespace Web.Infrastructure.Storage
{
    public class EFCFSession : ISession
    {
        DbContext _context;
        public EFCFSession(DbContext context)
        {
            _context = context;
        }

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

        public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T: class, new() {

            var query = All<T>().Where(expression);
            foreach (var item in query) {
                Delete(item);
            }
        }

        public void Delete<T>(T item) where T: class, new() {
            _context.Set<T>().Remove(item);
        }

        public void DeleteAll<T>() where T: class, new() {
            var query = All<T>();
            foreach (var item in query) {
                Delete(item);
            }
        }

        public void Dispose() {
            _context.Dispose();
        }

        public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T: class, new() {
            return All<T>().FirstOrDefault(expression);
        }

        public IQueryable<T> All<T>() where T: class, new() {
            return _context.Set<T>().AsQueryable<T>();
        }

        public void Add<T>(T item) where T: class, new() {
            _context.Set<T>().Add(item);
        }
        public void Add<T>(IEnumerable<T> items) where T: class, new() {
            foreach (var item in items) {
                Add(item);
            }
        }
        public void Update<T>(T item) where T: class, new() {
            //nothing needed here
        }
    }
}

Another interesting thing I found when doing this is that I couldn't use the same DB for the ReportingDB DbContext and the SiteDB DbContext without Code-First wiping the other out. Not a huge deal at the moment but could become an issue down the road.

So far I'm loving the idea of using POCO model classes and can't wait to try combine them with the MVC 3 Model Validation improvements!