2012-12-11 90 views
1

只要我不使用注释掉的using语句,以下代码就可以工作。当我使用using我得到The operation cannot be completed because the DbContext has been disposed使用声明和实体框架

public IQueryable<DTOs.FormQuestionDTO> GetForm(int id, int page = 0) 
{ 
    // FS stores pages starting with 1 
    page = page == 0 ? 1 : page; 

    //using (var db = new Models.FormEntities()) 
    //{ 
     var db = new Models.FormEntities(); 

     var questions = from fq in db.FormQuestions 
         join q in db.Questions on fq.QuestionId equals q.QuestionId 
         where (fq.FormId == id) && (fq.PageNumber == page) && fq.Disabled == false 
         orderby fq.DisplayOrder 
         select new { q.QuestionId, q.QuestionText, fq.DisplayOrder, fq.PageNumber }; 

     var dto = questions.Project().To<DTOs.FormQuestionDTO>(); 

     if (questions == null) 
     { 
      throw new HttpResponseException(HttpStatusCode.NotFound); 
     } 
     else 
     { 
      return dto; 
     } 
    //} 
} 

我最初的直觉是,在使用LINQ查询后立即处置的DbContext的,但把.Dipose()一个finally块的内部时,我得到了同样的错误。

这是怎么回事?我没有在C#中工作过一段时间,所以我可能错过了一些简单的东西。

+0

什么是堆栈跟踪? – SLaks

回答

5

实体框架LINQ提供程序使用deferred execution。这意味着直到迭代IQueryable为止,查询才会在数据库上执行。

发生什么事情是,在处理上下文后,某些东西会迭代您的查询,从而导致它尝试执行数据库查询。

您可以通过调用ToList()立即强制执行它。

var dto = questions.Project().To<DTOs.FormQuestionDTO>().ToList(); 
+0

谢谢,那是它。有没有一种等效的方法可以导致执行,但返回IQueryable类型的集合?或者我必须将返回的列表转换回IQueryable? – Jelling

+0

不是我没有。我倾向于将IQueryable视为未执行的查询,所以我认为它适合。其他将执行IQueryable查询的方法有['ToArray','ToDictionary'](http://msdn.microsoft.com/zh-cn/library/bb341635.aspx)等。 – jrummell

0

+1 ti @ jrummell。 原因你得到的错误是,当在using中声明的变量离开该范围时,将在其上释放DbContext的.Dispose()被调用。

如果你尝试执行,DbContext不再存在。

+0

您确定适用于此处吗?原始代码仍在使用{}的上下文中;看起来更像是DbContext由于延迟执行而尚未创建。 – Jelling

+1

@Jelling:他返回IQueryable,所以可能会在* using *语句的上下文之外迭代它。 –