为什么“Dispose”工作,而不是“使用(var db = new DataContext())”?

时间:2014-04-16 13:20:33

标签: c# asp.net asp.net-mvc razor

我正在创建一个由主题组成的论坛,这些主题由消息组成。

当我尝试使用以下命令在我的控制器中实现主题视图时

public ActionResult Topic(int id) //Topic Id
{
    using (var db = new DataContext())
    {
        var topic = db.Topics.Include("Messages").Include("Messages.CreatedBy").Include("CreatedBy").FirstOrDefault(x => x.Id == id);

        //include the messages for each topic, and when they were created so that the last message can be displayed on the topic page
        return topic != null ? View(topic) : View();
    }
}

当我尝试查看主题页面时出现此错误:

  

ObjectDisposedException未被用户代码

处理      

ObjectContext实例已被释放,不能再用于需要连接的操作。

错误似乎并不特定于某一行,因为当我删除有问题的行时,之前会出现相同的错误。

我通过使用:

解决了这个问题
DataContext db = new DataContext();

在控制器的开头,并且:

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

(并using取出)

虽然这有效,但我很好奇为什么"使用"不起作用,我不喜欢在整个控制器中打开连接,并在最后手动处理它。

4 个答案:

答案 0 :(得分:7)

您的任何实体是否启用了延迟加载?似乎在您的视图中有查询被执行但您在执行之前处理了您的上下文(因此错误说它已经被处理掉了)。如果将处理放在控制器Dispose方法中,视图将在处理控制器和上下文之前执行。

我建议安装Glimpse.Mvc5和Glimpse.EF6软件包。配置glimpse后,您可以看到在页面中执行的每个查询。您可能会惊讶地看到一些您不想要执行的其他查询。这就是我不建议您直接在视图中使用实体的原因。

答案 1 :(得分:3)

这种情况正在发生,因为LINQ实体通常是代理对象。如果您有类似MyEntity.ChildEntities的内容,则不执行基础SQL查询以获取这些对象,直到执行代码为止。如果您在视图中访问它们,则视图不会被绑定,直到操作方法返回,此时DbContext已经被释放。

生命周期看起来像这样:

  1. 致电行动方法
  2. 用于获取topic的外部查询运行,但视图中触发更多SQL查询的任何其他访问器尚未执行。
  3. 我们现在已经离开了操作方法,因此using刚刚处理了您的DbContext。
  4. MVC框架将模型绑定到视图,该视图触发实际执行任何剩余查询并因DbContext被释放而失败。
  5. 请求生命周期即将结束,因此控制器处理完毕。
  6. Here's a good resource on lazy loading with entities.

答案 2 :(得分:1)

这是延迟加载的一个问题,所以感谢正确方向的观点@Dismissile

一旦我使用了'。包括'加载Topic的每个虚拟属性,它工作正常:

var topic = db.Topics.Include("Messages").Include("Messages.CreatedBy").Include("CreatedBy").Include("Forum").Include("DeletedBy").FirstOrDefault(x => x.Id == id);

我想在没有我说的情况下,任何人都不可能知道我宣称哪些属性是虚拟的,抱歉!

顺便说一句,它在我在调试模式下检查属性之前有效,因为必须加载每个属性才能检查它

答案 3 :(得分:0)

您无法使用上下文返回视图或其他内容,因为这会导致在此处理上下文时出现问题。

在您的案例中使用using语句的正确方法是

public ActionResult Topic(int id) //Topic Id
{
    Topic topic = null; // topic is your POCO
    using (var db = new DataContext())
    {
        topic = db.Topics.Include("Messages").Include("Messages.CreatedBy").Include("CreatedBy").FirstOrDefault(x => x.Id == id);   
    }
    return topic != null ? View(topic) : View();

}
如果您使用声明,

也不做响应重定向。

见这里:Disposing Database context with using statement in MVC