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");
}
}