帮助 Windsor 和存储库以及工作单元模式

发布于 2024-11-28 07:37:22 字数 1250 浏览 1 评论 0原文

我有这些接口:

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 的构造函数code> 作为参数,并且此 DbContext 在 SqlUnitOfWork(上面的代码)中创建,并且我使用 Resolve 方法的重载传递此参数。

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

谢谢!

I have these interfaces:

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

I implement IUnitOfWork as follow:

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

The implementations of IBookRepository and IPersonRepository uses a constructor that takes a DbContext as a parameter, and this DbContext is created in the SqlUnitOfWork (code above) and I pass this parameter using an overload of the Resolve method.

My question is, is this the right way to do it? Is this a good practice?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半﹌身腐败 2024-12-05 07:37:22

使用 DI 容器作为服务定位器很难说是一个好的实践。除此之外,在解析接口时将DbContext传递给容器是一个泄漏抽象,因为这意味着您知道一些您不应该知道的具体实现。

相反,我会推荐构造函数注入,它会像这样:

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 容器,API 会有所不同,但概念是相同的。

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

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

Using a DI Container as a Service Locator can hardly be said to be good practice. In addition to that, passing the DbContext to the container while resolving an interface is a Leaky Abstraction because it implies that you know something about the concrete implementation that you should not.

Instead I would recommend Constructor Injection, which would go something like this:

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

Even though there's no explicit sharing of DbContext, this can be configured through the container. Since the context of this question indicates that Castle Windsor is the container being used, the default lifetime is already Singleton, so you don't have to explicitly set this up. With Castle Windsor, the DbContext will automatically be shared between the SqlUnitOfWork class and both repositories.

However, you can also explicitly configure the context to be shared, like this:

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

If you were to use another DI Container, the API would be different, but the concept is the same.

Bonus info: I don't know what the overall context is, but if this is to be used in a web application and DbContext is an Entity Framework or LINQ to SQL context, the correct lifetime configuration would instead be PerWebRequest as none of those context classes are thread-safe:

container.Register(Component.For<DbContext>().LifeStyle.PerWebRequest);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文