【问题标题】:Help with Windsor and Repository and Unit of Work patterns帮助 Windsor 和存储库以及工作单元模式
【发布时间】:2011-10-19 14:27:03
【问题描述】:

我有这些接口:

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();
}

我实现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();
    }
}

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

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

谢谢!

【问题讨论】:

  • 看看this article。它显示了类似的方法。它可能会给你一些想法。

标签: .net dependency-injection castle-windsor ioc-container


【解决方案1】:

将 DI 容器用作 Service Locator can hardly be said to be good practice。除此之外,在解析接口时将DbContext 传递给容器是Leaky Abstraction,因为这意味着您知道一些您不应该知道的具体实现。

我会推荐 Constructor Injection,它会是这样的:

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();
    }
}

即使DbContext 没有显式共享,也可以通过容器进行配置。由于这个问题的上下文表明 Castle Windsor 是正在使用的容器,因此默认生命周期已经是 Singleton,因此您没有必须显式设置它。使用 Castle Windsor,DbContext 将自动在 SqlUnitOfWork 类和两个存储库之间共享。

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

container.Register(Component.For<DbContext>().LifeStyle.Singleton);

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

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

container.Register(Component.For<DbContext>().LifeStyle.PerWebRequest);

【讨论】:

  • 构造函数注入不是不是最优吗? Web 请求可能只需要 SqlUnitOfWork.People.Get(322);,但 bookRepository 的实例也已创建(因为它在构造函数中),即使它不需要
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-27
  • 2016-05-10
相关资源
最近更新 更多