2

在我的 MVC 控制器中,我使用的是 IoC 容器(Ninject),但不确定如何最好地使用实体框架 ObjectContext。

目前,我正在做类似的事情:

using(var context = new MyObjectContext())
{
     var stuff = m_repository.GetStuff(context);
}

从尽可能短的时间内保持数据库连接打开的角度来看,这是最好的管理方式。

如果我要根据每个请求通过 Ninject 创建 ObjectContext,这显然会使数据库连接打开太久。

上面的代码也会变成......

var stuff = m_repository.GetStuff(m_myObjectContext);

(我什么时候处理上下文......?)

我应该为 ObjectContext 创建一个工厂并通过 DI 传递它吗?这会放松耦合,但是如果没有简单的方法来维护 ObjectContext 的接口(我知道),这真的有助于可测试性吗?

有没有更好的办法?谢谢

4

1 回答 1

3

从尽可能短的时间内保持数据库连接打开的角度来看,这是最好的管理方式。

如果我要根据每个请求通过 Ninject 创建 ObjectContext,这显然会使数据库连接打开太久。

Entity Framework 将在执行每个查询后直接关闭连接(从外部提供打开的连接时除外),因此您执行此类操作的论点不成立。

过去,我曾经通过业务逻辑(准确地说是我的命令处理程序)控制上下文(创建、提交和处置它),但缺点是您需要将此上下文传递给所有其他方法和所有依赖项。当应用程序逻辑变得更复杂时,这会导致代码的可读性和可维护性降低。

出于这个原因,我转向了一个模型,在该模型中,工作单元(您的MyObjectContext)在业务逻辑的控制之外被创建、提交和处置。这允许您将工作单元注入所有依赖项并为所有对象重用相同的工作单元。缺点是这会使您的 DI 配置更加困难。您需要确保的一些事项:

  1. 必须根据 Web 请求或在一定范围内创建工作单元。
  2. 工作单元必须在请求或作用域的末尾被释放(尽管如果不释放它可能不是问题DbContext,因为底层连接已关闭并且DbContext没有实现终结器)。
  3. 您需要明确提交工作单元,但您不能在 Web 请求结束时执行此操作,因为此时您不知道提交是否安全(因为您不想提交业务逻辑抛出异常,但在请求结束时无法正确检测这是否真的发生)。

我可以给您的一个提示是围绕命令处理程序对系统中的业务逻辑进行建模,因为这允许您定义一个处理事务行为(提交工作单元,甚至可能在数据库事务中运行所有内容)的单个装饰器一个点。这个装饰器可以包裹在系统中的每个处理程序周围。

我必须承认我不知道如何使用 Ninject 注册泛型类型和泛型装饰器,但是当您在 Stackoverflow 上提问时,您可能会很快得到答案。

于 2012-04-27T07:27:32.903 回答