在控制器的函数之外声明DBContext是不好的做法

本文关键字:DBContext 声明 控制器 函数 | 更新日期: 2023-09-27 18:05:18

假设我有一个像这样的控制器:

public class MyController : Controller
{
    private MyDBContext db = new MyDBContext();
    public ActionResult Index()
    {
        return View(db.Items.ToList());
    }
...

通常,当我需要进行EF调用时,我会在我使用它的函数中实例化DBContext,并将其包装在using语句中,如下所示:

    public ActionResult Index()
    {
        using(MyDBContext db = new MyDBContext())
        {
            return View(db.Items.ToList());
        }
    }

我在www.asp.net网站上找到了第一个例子,这似乎是一个有信誉的来源(对吧?),但我担心每次使用后上下文没有被手动处理。

在没有using语句的函数范围之外定义的上下文是一种不好的做法吗?

在控制器的函数之外声明DBContext是不好的做法

如果你有这样的东西

protected override void Dispose(bool disposing)
{
    db.Dispose();
    base.Dispose(disposing);
}

由于Controller是Disposable,所以没有问题但一般来说,我试图在我的控制器和我的模型之间有一个更好的分离。

第一种方法是"推荐的"方法,因为当控制器被处置时上下文也会被处置。由于控制器在请求的生命周期中仍然存在,因此您可以确保上下文也将在整个时间内挂起。在上下文中使用using是危险的,因为上下文是在请求中的不同点被处理的,如果在它被处理后访问它可能会导致问题。这里可能没有问题,因为返回值在using块中,但假设您做了以下操作:

List<Item> items;
using(MyDBContext db = new MyDBContext())
{
    items = db.Items.ToList();
}
return View(items);

当你第一次访问一个懒惰加载的导航属性时,你会很痛苦。虽然您没有在代码中犯这个错误,但通常很容易犯这个错误。如果你在上下文中完全避免了using,那么你总是好的。

也就是说,最好的方法是实际使用依赖注入。无论出于何种意图和目的,您的上下文都应该被视为单例—您不希望多个实例到处浮动,因为这将导致灾难。使用DI容器是确保实现这一目标的好方法,无论在何处以多少种不同的方式使用上下文。使用哪个DI容器完全是个人的选择。我更喜欢Ninject,但也有很多其他的选择可能更适合你的个人风格。无论您使用哪种方式,都应该有一些使用"请求范围"的选项。这就是你想要在上下文中使用的,因为它确保每个请求只有一个实例,但每个请求都有自己的实例。