为什么我需要ToList()来避免处置上下文错误?

时间:2014-12-16 17:27:23

标签: c# linq entity-framework asp.net-mvc-5

我正在编写一些代码来使用EntityFrameWork访问数据库。代码是:

public IEnumerable<Rows> GetRows(int id)
{
    using (var context = new ApplicationDbContext())
    {
        var repository = new EntityFrameWorkRepository<int, RowEntity>(context);
        //need a ToList() here to prevent disposed dbcontext errors
        return repository.GetRowsFromDb(id).ToList();
    }
}

GetRowsFromDb()使用LINQ查询数据库并使用id过滤结果。

我最初在没有ToList()调用的情况下编写了上述方法,但是当我尝试访问返回的IEnumerable中的对象时,我会得到一个关于dbcontext已被处置的异常。我不明白上面的代码如何解决问题,虽然它确实有效。我假设ToList()是深度复制对象,这可能提供了与上下文/数据库的必要分离,但是原始对象肯定可以使用吗?

4 个答案:

答案 0 :(得分:8)

您需要调用ToListToArray或枚举EF返回的数据的其他方法的原因是LINQ中的查询执行延迟:数据在您明确接受之前不会处理。当您的方法返回已获取查询数据的上下文时,您的using块会快速处理发生的事件),从而导致您看到的异常。

这样做是为了使代码不花时间处理您不需要的数据。例如,您可以编写开始读取客户端数据的代码,并在中间停止。如果查询执行没有推迟,你就会花费时间和内存来获得&#34; tail&#34;查询只是扔掉它。延迟执行使您掌控:您可以根据自己的需要决定要保留哪些数据,或者根据您计划对数据执行的操作将整个集合带到内存中。

答案 1 :(得分:7)

如果你没有调用.ToList(),那么在你的using子句完成后将对进行评估,因此在评估查询之前将处理数据上下文。

IMO,您应该考虑让您的存储库处理此问题(通过调用.ToList()),否则此问题代表泄漏的实现细节。

答案 2 :(得分:1)

没有ToList(),您只返回枚举器而不是实际的对象集合。尝试访问集合时将获取实际对象。但在这种情况下,您需要的是上下文和存储库,因为您从数据库访问它们。但由于它已经超出了using条款的范围,因此两者都被处理掉了。

答案 3 :(得分:1)

  

我假设ToList()深度复制对象

不完全 - 在您致电ToList之前,您拥有的只是查询。在您枚举或通过ToListToArrayetc将其转换为具体集合之前,您不会获得结果

  

当然原始对象应该可用吗?

没有 - 它已被处理掉,这是告诉系统该对象完成其工作而不再需要的方式。您仍有未执行查询的事实不会使上下文保持可用状态。