我正在创建一个由主题组成的论坛,这些主题由消息组成。
当我尝试使用以下命令在我的控制器中实现主题视图时
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
取出)
虽然这有效,但我很好奇为什么"使用"不起作用,我不喜欢在整个控制器中打开连接,并在最后手动处理它。
答案 0 :(得分:7)
您的任何实体是否启用了延迟加载?似乎在您的视图中有查询被执行但您在执行之前处理了您的上下文(因此错误说它已经被处理掉了)。如果将处理放在控制器Dispose方法中,视图将在处理控制器和上下文之前执行。
我建议安装Glimpse.Mvc5和Glimpse.EF6软件包。配置glimpse后,您可以看到在页面中执行的每个查询。您可能会惊讶地看到一些您不想要执行的其他查询。这就是我不建议您直接在视图中使用实体的原因。
答案 1 :(得分:3)
这种情况正在发生,因为LINQ实体通常是代理对象。如果您有类似MyEntity.ChildEntities
的内容,则不执行基础SQL查询以获取这些对象,直到执行代码为止。如果您在视图中访问它们,则视图不会被绑定,直到操作方法返回,此时DbContext已经被释放。
生命周期看起来像这样:
topic
的外部查询运行,但视图中触发更多SQL查询的任何其他访问器尚未执行。using
刚刚处理了您的DbContext。答案 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();
}
如果您使用声明,也不做响应重定向。