使用Entity Framework和Castle Windsor

Pau*_*lor 24 asp.net-mvc entity-framework castle-windsor inversion-of-control

我使用Entity Framework数据库优先方法为MVC应用程序生成DbContext/POCO模型.我想避免在我的控制器中依赖DbContext来使我能够根据需要切换到另一个持久性提供程序(例如用于单元测试).

为此,我想使用Castle Windsor IoC容器.我计划将DbContext注册为IUnitOfWork服务并注册一个通用的IRepository服务,我将使用它来访问和使用模型中的聚合根.

我是Windsor的新手,并且无法找到关于在EF中使用它的更多信息,我有几个问题:

  • 如果我想将EF与应用程序分离,这是一种合理的方法吗?
  • 如何安装/注册IUnitOfWork和通用IRepository服务?

Pau*_*lor 25

所以,一些结论.我想我会写这个,以防其他人试图使用/单元测试EF,Windsor和MVC.

首先,由于DbContext同时实现了Repository和Unit of Work模式,因此您需要了解这些实现是否会提供服务,或者您是否需要创建自己的实现.

我选择按照DDD模式创建自己的Repository:每个聚合根一个.原因是:封装查询代码,防止它泄漏到应用程序层,并且在测试应用程序控制器时能够更容易地进行模拟.我创建了一个基于的通用存储库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();
}
Run Code Online (Sandbox Code Playgroud)

然后,我为我的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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一部分是扩展Entity Framework上下文类以实现IDbContext,并将Set()方法隐藏为返回IDbSet而不是DbSet:

public partial class MyEntities : IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }
}
Run Code Online (Sandbox Code Playgroud)

完成所有这些(以及Windsor文档中说明的ControllerFactory注册),让Windsor根据需要将IRepository对象(或IDbContext)注入控制器构造函数变得微不足道:

public ControllerBase(IRepository<Contact> repo)
{
    _repo = repo;
}
Run Code Online (Sandbox Code Playgroud)

在Repository单元测试中,可以使用模拟IDbContext支持真实存储库实例:

mocks = new MockRepository();
context = mocks.StrictMock<IDbContext>();
repo = new Repository<Contact>(context);
Run Code Online (Sandbox Code Playgroud)

在Controller单元测试中,可以使用模拟存储库:

mocks = new MockRepository();
repo = mocks.StrictMock<IRepository<Contact>>();
ContactController controller = new ContactController(repo);
Run Code Online (Sandbox Code Playgroud)

  • 感谢您抽出宝贵时间提供示例代码并总结:-) (2认同)