我用的是实体框架数据库第一的方针,以产生一个MVC应用程序的DbContext / POCO模型。 我想避免的DbContext具有依赖性在我的控制器,使我能够切换到另一个持久性提供,因为我需要(例如用于单元测试目的)。
要做到这一点,我想使用的温莎城堡IoC容器。 我打算注册的DbContext作为IUnitOfWork服务,并注册一个通用IRepository服务,实现它,我会用它来访问并与模型汇总基础工作。
我是新来温莎一直没能找到有关使用它与EF很多信息,我有几个问题:
- 这是一种合理的做法,如果我想从应用程序分离EF?
- 如何安装/注册IUnitOfWork和通用IRepository服务?
因此,一些结论。 我以为我会写这件事的情况下,它是利用别人试图使用/单元测试EF,温莎和MVC一起。
首先,如实现的DbContext的工作模式既库和单位,你需要查看这些实现是否会担任或是否需要创建自己的。
我选择创建自己的资源库,在DDD模式如下:每个聚合根之一。 理由:封装查询代码,以防止它泄漏到应用层,和测试应用程序的控制器时,能够更容易地嘲笑。 我创建了基于通用库IRepository<TEntity>
有很多的例子在那里。 我发现这是一个很好的一个: http://architects.dzone.com/articles/implementing-repository
在另一方面,我决定放弃IUnitOfWork服务,选择了默认的实现来代替。 不过,我创建了一个抽象IDbContext(不知道为什么微软没有这样做本身),从而使测试存储库服务时,我可以嘲笑的DbContext。
我给IDbContext只,我想在资源库中使用的DbContext的成员。 所以:
public interface IDbContext: IDisposable
{
Database Database { get; }
DbEntityEntry Entry(object entity);
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
然后,我创造了我的IDbContext和IRepository服务设施温莎和安装程序:
public class EntityFrameworkFacility: AbstractFacility
{
protected override void Init()
{
Kernel.Register(Component.For<IDbContext>()
.ImplementedBy<MyEntities>()
.LifestylePerWebRequest(),
Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>))
.LifestylePerWebRequest());
}
}
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<EntityFrameworkFacility>();
}
}
最后一块是扩展的实体框架上下文类来实现IDbContext,和阴影设置()方法返回IDbSet而非DbSet:
public partial class MyEntities : IDbContext
{
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
}
与此全部到位(和在温莎文档中示出的的ControllerFactory登记)时,它变得微不足道得到温莎注入IRepository对象(或IDbContext)到控制器的构造,根据需要:
public ControllerBase(IRepository<Contact> repo)
{
_repo = repo;
}
在库单元测试,真正的存储库实例可以使用模拟IDbContext备份:
mocks = new MockRepository();
context = mocks.StrictMock<IDbContext>();
repo = new Repository<Contact>(context);
在控制器单元的测试中,一个模拟信息库可以使用:
mocks = new MockRepository();
repo = mocks.StrictMock<IRepository<Contact>>();
ContactController controller = new ContactController(repo);