EF6 DbContext IOC 依赖

EF6 DbContext IOC Dependency

我在 Windows 服务/控制台应用程序中使用 EF6。我已经成功 为我的业务层接口和实现实现了 IOC/DI。 使用构造函数注入。我也在使用对象数据库、任务并行库。为了更好的表现,我很高兴。

还使用 System.IO.Abstractions 使我的代码更易于测试。

EF6 使用 .tt 文件为所有域实体创建 POCO 类,这些文件相当 便利。为了执行数据库查询,我在每个地方都写了

using(var db = new MyContext())
{
// code reading from/writing to database
...
...
}

我知道这是不正确的做法,并且会在我的代码的各个地方发出噪音。 我想让它松耦合。现在进行我的数据库操作 - 我是 对如何前进以使其更具可测试性和松散耦合感到困惑。任何人都可以给我一个很好的例子,可以参考的文章。

我想要实现的 2 件主要事情是对 连接字符串配置(用于各种服务器部署)并在我的代码中 DbContext 非常松散耦合。

为了解决解耦(和测试)问题,您可以为您的 DbContext (IMyDbContext) 创建自己的接口,并重新公开所有类型化实体 DbSetsSaveChanges(),可能还有其他一些方法。你也应该让这个界面Disposable

public interface IMyDbContext : IDisposable
{
    IDbSet<Foo> Foos { get; set; }
    IDbSet<Bar> Bars { get; set; }

    int SaveChanges();
    DbEntityEntry<T> Entry<T>(T entity) where T : class;
}

(您也可以考虑接口的只读和读写版本)

然后更改您的具体 DbContext 以实现此接口。您现在与 DbContext 合理分离(用于单元测试等),但仍然可以使用 IQueryable、固有工作单元和 DbContext 提供的缓存.

然后,这里有两个选项可以将 IMyDbContext 注入您的业务/服务 类

  1. IDbContext
  2. 的构造函数注入

  1. 创建用于创建具体 DbContext 的工厂方法和工厂接口,然后对 IMyDbContextFactory 工厂接口进行构造函数注入(再次需要接口,而不是具体工厂用于模拟测试目的)。

这里的选择取决于您需要用 DbContext 做什么。 #1 在 IoC 容器中配置可能很棘手,因为您需要将生命周期管理移交给容器。但是,如果可以为每个请求配置新实例,那么这在 Web 应用程序中可能是有益的,这样如果请求(假定为单线程)可以将其用作缓存。

我个人更喜欢#2,因为它允许直接管理上下文:

using(var db = _myContextFactory.CreateDB())
{
    db.SaveChanges();
}

但很明显,我们随后失去了缓存等长期存在的上下文的任何潜在好处。但如果需要,还有许多其他缓存替代技术。

一个警告:DbContext 根本不是线程安全的 - 如果您使用 TPL,请确保每个任务都获得自己的 DbContext 实例 - 例如使用 Parallel.For / ForEachlocalinit 重载来实例化它。