为此,我想使用Castle Windsor IoC容器。我计划将DbContext注册为IUnitOfWork服务,并注册通用的IRepository服务,我将使用它来实现访问和使用模型中的聚合根。
我是Windsor的新人,还没有找到很多有关使用EF的信息,我有几个问题:
>如果我想从应用程序中分离EF,这是一个合理的方法吗?
>如何安装/注册IUnitOfWork和通用的IRepository服务?
解决方法
首先,由于DbContext同时实现了Repository和Work of Work模式,您需要查看这些实现是否可以提供,还是需要创建自己的。
我选择创建自己的存储库,遵循DDD模式:每个聚合根一个。原因:封装查询代码,防止漏洞进入应用层,并能够在测试应用控制器时更轻松地模拟。我创建了一个基于IRepository< TEntity>的通用存储库。那里有很多例子。我发现这是一个很好的:http://architects.dzone.com/articles/implementing-repository
另一方面,我决定删除IUnitOfWork服务,而不是选择默认实现。但是,我创建了一个IDbContext抽象(不知道为什么微软本身没有这样做),所以我可以在测试Repository服务时嘲笑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服务创建了一个Windsor设施和安装程序:
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>(); } }
最后一个部分是将Entity Framework上下文类扩展为实现IDbContext,并将Set()方法映射为返回IDbSet而不是DbSet:
public partial class MyEntities : IDbContext { public new IDbSet<TEntity> Set<TEntity>() where TEntity : class { return base.Set<TEntity>(); } }
有了这一切(Windsor文档中说明的ControllerFactory注册),Windsor将IRepository对象(或IDbContext)注入到控制器构造函数中变得非常简单:根据需要:
public ControllerBase(IRepository<Contact> repo) { _repo = repo; }
在Repository单元测试中,真实的存储库实例可以使用模拟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);