Repository & Unit of Work Pattern for Entity Framework using Dependency Injection
I tried the T4-Template from http://efrepository.codeplex.com, but I'm struggling with the DI (uses StructureMap) Example code. It's just not enough for a DI beginner like me. It doesn't even compile.
I already have done a few sample 开发者_开发问答projects with its Non-DI Template. And it worked out great. I love, that it generates all necessary repositories and that I can easily customize and extend them. But I can't get the DI Examples working. Are there any similar projects (with better docs)?
I normally use the following setup with EF end Structure map: (brace yourself, bunch o' code coming up).
This is the base interface we'll use to inject our controllers:
public interface ISession : IDisposable
{
void CommitChanges();
void Delete<T>(Expression<Func<T, bool>> expression) where T : class, new();
void Delete<T>(T item) where T : class, new();
void DeleteAll<T>() where T : class, new();
T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
IQueryable<T> All<T>() where T : class, new();
void Add<T>(T item) where T : class, new();
void Add<T>(IEnumerable<T> items) where T : class, new();
void Update<T>(T item) where T : class, new();
}
And here an ISession
implementation with EF in mind:
public class EntityFrameworkSession : ISession
{
// MyContext is a class inheriting from EF's DbContext
readonly DbContext _context;
public EntityFrameworkSession(DbContext context)
{
_context = context;
}
public void CommitChanges()
{
_context.SaveChanges();
}
public void Delete<T>(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>(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();
}
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
}
}
Now this ISession
implementation is not very handy to inject because, while being nice and generic, it doesn't have a default constructor, so the way to solve it is by writing a small wrapper that only exposes a parameter-less constructor:
/// <summary>
/// This is the EF site alternative
/// </summary>
public class SiteEFSession : EntityFrameworkSession
{
public SiteEFSession() : base(new MyContext())
{ }
}
Now we can easily inject it. We set it up in StructureMap
as follows:
ObjectFactory.Initialize(x =>
{
x.For<ISession>().Use<SiteEFSession>();
});
And if you have, for instance, an MVC style controller:
public class HomeController : Controller
{
private readonly ISession _session;
// ISession will be injected automatically
public HomeController(ISession session)
{
_session = session;
}
}
There you go. It's a helluva lot of code but you can pretty much copy/paste it into your solution and you should be good to go.
精彩评论