将DbContext注入到Repository类库中

8
我的解决方案中的项目设置如下:
  • App.Data
  • App.Models
  • App.Web
在 App.Data 中,我使用 Entity Framework 访问我的数据,并使用一堆仓储来抽象化与它的交互。出于明显的原因,我希望我的 App.Web 参考的只是 App.Data 项目,而不是 Entity Framework。
我使用构造函数注入给我的控制器提供一个仓储容器的引用,看起来像这样:
public interface IDataRepository
{
    IUserRepository User { get; set; }
    IProductRepository Product { get; set; }

    // ...
}

public class DataRepository : IDataRepository
{
    private readonly AppContext _context;

    public DataRepository(AppContext context)
    {
        _context = context;
    }

    // ...
}

DataRepository将拥有一个AppContext对象(该对象继承自Entity Framework的DbContext),所有子存储库都将使用它来访问数据库。

最终我们来到了我的问题: 考虑到它是一个代码库,并且没有入口点,我如何在DataRepository上使用构造函数注入? 我不能在App.Web中引导AppContext,因为那样我就必须从该项目引用Entity Framework。

或者我只是做了些愚蠢的事情吗?


这不是对您问题的答案,而是建议您尝试定义一个单一的 IRepository<T> 接口,而不是定义许多存储库接口。详见此处。这样可以获得更大的灵活性。 - Steven
6
@Steven,感谢您的评论。出于以下原因,我更喜欢使用特定的代码仓库:“代码仓库是被建模领域的一部分,而该领域并不是通用的。并非每个实体都可以被删除,也不是每个实体都可以被添加,也不是每个实体都有一个代码仓库。”参考链接:https://dev59.com/IHM_5IYBdhLWcg3wyWWt - ajbeaven
1个回答

12

您可以在App.Data中定义一个RepositoryConnection类,它充当上下文的包装器,消除了在App.Web中引用EF的需求。如果您正在使用IoC容器,可以控制RepositoryConnection类的生存期,以确保所有Repository实例都使用相同的上下文。这是一个简化的示例...

public class RepositoryConnection
{
    private readonly AppContext _context;

    public RepositoryConnection()
    {
        _context = new AppContext();
    }

    public AppContext AppContext { get { return _context; } }
}

public class DataRepository : IDataRepository
{
    private readonly AppContext _context;

    public DataRepository(RepositoryConnection connection)
    {
        _context = connection.AppContext;
    }

// ...
}

如果所有类都获取相同的上下文,那么没有人会处理EF上下文,这是不好的,非常糟糕。EF上下文的设计理念是您实例化、使用和处理它。 - Bruno Brant
@BrunoBrant 您说得非常正确 - Context 应该尽可能短暂,这个答案完全支持这一点。我们有一个 RepositoryConnection 作为程序集之间的 桥梁 并不会改变这一事实。RepositoryConnection 和因此 Context 注册为 每个 Web 请求。每个 RepositoryConnection (和因此 Context) 将存在于单个 Web 请求的范围内,因此将存活几秒钟。一旦 Web 请求完成,DI 管理的类将超出范围并被 Disposed() - qujck
@qujck,我可能漏掉了什么,但是谁能保证立即执行 Dispose()?据我所知,ASP.Net没有提供这样的保证。 - Bruno Brant
3
所以在你上面举的例子中,RepositoryConnection 应该是 IDisposable,而 Dispose 方法仅调用 _context.Dispose() - ajbeaven
@ajbeaven 是的,你完全正确 - 实例化其他对象的对象完全负责处理它实例化的对象的释放。如果 IoC 容器实例化了一个对象,则必须对其进行处理。如果我的类直接实例化可处理对象,则应确保它们在正确的时间被处理。由于这个事实与评论中的问题有关,而不是直接与实际问题有关,所以我不会更新我的答案。 - qujck
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接