我在 Windows 服务/控制台应用程序中使用 EF6。我已经成功 为我的业务层接口(interface)和实现实现了 IOC/DI。 使用构造函数注入(inject)。我也在使用对象数据库、任务并行库。以获得更好的性能,我对此感到满意。
同时使用 System.IO.Abstractions使我的代码更易于测试。
EF6 使用 .tt 文件为所有域实体创建 POCO 类 便利。为了执行数据库查询,我在每个地方都写了
using(var db = new MyContext())
{
// code reading from/writing to database
...
...
}
我知道这不是正确的做法,并且会在我的代码的各个地方发出噪音。 我想让它松耦合。现在进行我的数据库操作 - 我是 对如何前进以使其更具可测试性和松散耦合感到困惑。任何人都可以给我一个很好的例子,可以引用的文章。
我想要实现的 2 件主要事情是对
连接字符串配置(用于各种服务器部署)并使 DbContext
在我的代码中非常松散地耦合。
最佳答案
为了解决耦合(和测试)问题,您可以为您的 DbContext
(IMyDbContext
) 创建自己的接口(interface),并重新公开所有类型化实体 DbSets
、SaveChanges()
,可能还有一些其他方法。您还应该将此接口(interface)设置为 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;
}
(您还可以考虑接口(interface)的只读和读写版本)
然后更改您的具体 DbContext
以实现此接口(interface)。您现在与 DbContext
合理分离(用于单元测试等),但仍然可以访问 IQueryable
的有用性、工作的固有单元以及由DbContext
。
然后,这里有两个选项可以将 IMyDbContext
注入(inject)到您的业务/服务类中
IDbContext
的构造函数注入(inject)
或
- 为创建具体的
DbContext
创建一个 Factory 方法和一个 Factory 接口(interface),然后对IMyDbContextFactory
工厂接口(interface)进行构造函数注入(inject)(您需要接口(interface),而不是混凝土工厂,同样用于模拟测试目的)。
此处的选择取决于您需要对 DbContext
执行的操作。 #1 在 IoC 容器中配置可能很棘手,因为您需要将生命周期管理移交给容器。但是,如果可以为每个请求配置新实例,那么这在 Web 应用程序中可能是有益的,这样如果请求(假定为单线程)可以将其用作缓存。
我个人更喜欢#2,因为它允许直接管理上下文:
using(var db = _myContextFactory.CreateDB())
{
db.SaveChanges();
}
但很明显,我们随后失去了缓存等长期存在的上下文的任何潜在好处。但如果需要,还有许多其他缓存替代技术。
一个警告:DbContext
根本不是线程安全的 - 如果您使用 TPL,请确保每个任务都获得自己的 DbContext
实例 - 例如使用 Parallel.For
/ForEach
的 localinit
重载来实例化它。
关于c# - EF6 DbContext IOC 依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27864702/