As requested here's an example of abstracting away EF as much as I was able whilst not requiring a seperate repository layer and using a service type approach instead (don't sue me for spelling errors :))
NOTE: Example was using Code first methodology of Entity Framework.
public interface IDataContext { IDbSet<Address> Addresses { get; set; } IDbSet<Contact> Contacts { get; set; } System.Data.Entity.Database Database { get; } DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class; int SaveChanges(); } public class MyDataContext : DbContext, IDataContext { public IDbSet<Address> Addresses { get; set; } public IDbSet<Contact> Contacts { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); } } Using a service layer is primarily where I will now store my business logic
public class BaseService { protected readonly IDataContext DataContext; public BaseService(IDataContext dataContext) { DataContext = dataContext; } } Potentially for mocking I might consider creating an interface for each service I create
public interface IAddressService { IEnumerable<Address> All(int id); Address GetById(int id); IEnumerable<Address> GetAddressWithinRange(string street, int rangeInMetres); } public class AddressService : BaseService, IAddressService { public AnalogService(IG5DataContext dataContext) : base(dataContext) { } public IEnumerable<Address> All() { return DataContext.Addresses.Where(p => !p.Deleted).ToList(); } public Address GetById(int id) { return DataContext.AnalogInputs.Find(id); } public IEnumerable<Address> GetAddressWithinRange(string street, int rangeInMetres) { return DataContext.Addresses .AsQueryable() .Where(p => p.Street == street && p.DistanceFromCentre < rangeInMetres); .ToList(); } // Other business methods here private IQueryable<Address> AsQueryable(Machinery machinery) { return DataContext.Entry(machinery).Collection(v => v.AnalogReadings).Query(); } } Then using an IOC container (Ninject, AutoFac, Unity are a few I've used. Or see this blog by Scott Hanselman for a list of what's around) I would inject these into my controller. The setup of the dependency registration would be dependant on the IOC implementation.
public class AddressController { private readonly IDataContext _dataContext; private readonly IAddressService _addressService; public AddressController(IDataContext dataContext, IAddressService addressService) { _dataContext = dataContext; _addressService = addressService; } [HttpGet] public ActionResult Index() { var addresses = _addressService.All(); return View("Index", addresses); } [HttpGet] public ActionResult Details(int addressId) { var address = _addressService.GetById(id); if(address == null) return HttpNotFound(); return View("Address", address); } [HttpPost] public ActionResult Details(Address address) { var model = _addressService.GetById(address.Id); if(address == null) return HttpNotFound(); // I might consider using A mapping framework like AutoMapper here. Not sure if this is correct // syntax but hopefully you get the point Mapper.Map(address, model); _dataContext.SaveChanges(); return RedirectToAction("Details"); } }