EF6 DbContext IOC依赖

时间:2015-01-09 16:13:05

标签: c# entity-framework visual-studio-2013 dependency-injection windows-services

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

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

EF6使用完全相同的.tt文件为所有域实体创建POCO分支 便利。为了执行数据库查询,我正在编写每个地方

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

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

我想要实现的两件大事就是要有更多的控制权 连接字符串配置(用于各种服务器部署)以及DbContext在我的代码中非常松散地耦合。

1 个答案:

答案 0 :(得分:10)

要解决脱钩(和测试)问题,您可以为DbContextIMyDbContext)创建自己的界面,并重新公开所有已键入的实体DbSets,{{1} },可能还有一些其他方法。您还应该创建此接口SaveChanges()

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. OR

    1. 创建一个Factory方法和一个Factory接口,用于创建具体的DbContext,然后对IMyDbContextFactory工厂界面进行构造函数注入(您将再次想要接口,而不是具体工厂)用于模拟测试目的)。
    2. 此处的选择取决于您对DbContext的需求。在IoC容器中配置#1可能很棘手,因为您需要将生命周期管理移交给容器。但是,如果可以为每个请求配置新实例,那么这可能对Web应用程序有益,因此如果请求(假设单个线程)可以将其用作缓存。

      我个人更喜欢#2,因为这样可以直接管理上下文:

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

      但显然,我们失去了长期上下文(如缓存)的任何潜在好处。但是,如果需要,还有许多其他替代技术可用于缓存。

      有一点需要注意:DbContext并非线程安全 - 如果您使用的是TPL,请确保每个任务都获得自己的DbContext实例 - 例如使用localinit / Parallel.For的{​​{1}}重载来实例化它。