帮助Windsor和Repository以及工作单元模式

Gus*_*tav 5 .net dependency-injection castle-windsor ioc-container

我有这些接口:

public interface IUnitOfWork
{
    IPersonRepository People { get; }
    IBookRepository Books { get; }
    int Commit();
}

public interface IBookRepository
{
    Book GetBookById(int id);
    IQueryable<Book> GetAllBooks();
}

public interface IPersonRepository
{
    Person GetPersonById(int id);
    IQueryable<Person> GetAllPeople();
}
Run Code Online (Sandbox Code Playgroud)

我实现IUnitOfWork如下:

public class SqlUnitOfWork : IUnitOfWork
{
    private readonly DbContext dbContext;

    public SqlUnitOfWork()
    {
        dbContext = new DbContext("name=SQLContainer");
    }

    public IPersonRepository People
    {
        get { return IoC.Container.Resolve<IPersonRepository>(new { DbContext = dbContext }); }
    }

    public IBookRepository Books
    {
        get { return IoC.Container.Resolve<IBookRepository>(new { DbContext = dbContext }); }
    }

    public int Commit()
    {
        return dbContext.SaveChanges();
    }
}
Run Code Online (Sandbox Code Playgroud)

实现IBookRepositoryIPersonRepository使用构造函数,该构造函数将a DbContext作为参数,并且此DbContext是在SqlUnitOfWork(上面的代码)中创建的,并且我使用Resolve方法的重载传递此参数.

我的问题是,这是正确的方法吗?这是一个好习惯吗?

谢谢!

Mar*_*ann 8

使用DI容器作为服务定位器几乎不是一个好习惯.除此之外,DbContext在解析接口时将其传递给容器是Leaky Abstraction,因为它意味着您了解了一些您不应该具体实现的内容.

相反,我会建议构造函数注入,这将是这样的:

public class SqlUnitOfWork : IUnitOfWork
{
    private readonly DbContext dbContext;
    private readonly IPersonRepository personRepository;
    private readonly IBookRepository bookRepository;

    public SqlUnitOfWork(DbContext dbContext,
         IPersonRepository personRepository, IBookRepository bookRepository)
    {
        if (dbContext == null)
            throw new ArgumentNullException("dbContext");
        if (personRepository == null)
            throw new ArgumentNullException("personRepository");
        if (bookRepository = null)
            throw new ArgumentNullException("bookRepository");

        this.dbContext = dbContext;
        this.personRepository = personRepository;
        this.bookRepository = bookRepository;
    }

    public IPersonRepository People
    {
        get { return this.personRepository; }
    }

    public IBookRepository Books
    {
        get { return this.bookRepository; }
    }

    public int Commit()
    {
        return this.dbContext.SaveChanges();
    }
}
Run Code Online (Sandbox Code Playgroud)

即使没有明确的共享DbContext,也可以通过容器进行配置.由于这个问题的背景表明,温莎城堡是正在使用的容器,默认的寿命已经是单身,所以你不要明确此设置.使用Castle Windsor,DbContext将在SqlUnitOfWork类和两个存储库之间自动共享.

但是,您还可以显式配置要共享的上下文,如下所示:

container.Register(Component.For<DbContext>().LifeStyle.Singleton);
Run Code Online (Sandbox Code Playgroud)

如果您要使用另一个DI容器,API会有所不同,但概念是相同的.

额外信息:我不知道整体上下文是什么,但是如果要在Web应用程序中使用它并且DbContext是实体框架或LINQ to SQL上下文,那么正确的生命周期配置将是PerWebRequest,而不是那些上下文类是线程安全的:

container.Register(Component.For<DbContext>().LifeStyle.PerWebRequest);
Run Code Online (Sandbox Code Playgroud)