我正在编写一些代码来使用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()是深度复制对象,这可能提供了与上下文/数据库的必要分离,但是原始对象肯定可以使用吗?
答案 0 :(得分:8)
您需要调用ToList
,ToArray
或枚举EF返回的数据的其他方法的原因是LINQ中的查询执行延迟:数据在您明确接受之前不会处理。当您的方法返回已获取查询数据的上下文时,您的using
块会快速处理发生的事件),从而导致您看到的异常。
这样做是为了使代码不花时间处理您不需要的数据。例如,您可以编写开始读取客户端数据的代码,并在中间停止。如果查询执行没有推迟,你就会花费时间和内存来获得&#34; tail&#34;查询只是扔掉它。延迟执行使您掌控:您可以根据自己的需要决定要保留哪些数据,或者根据您计划对数据执行的操作将整个集合带到内存中。
答案 1 :(得分:7)
如果你没有调用.ToList()
,那么在你的using
子句完成后将对进行评估,因此在评估查询之前将处理数据上下文。
IMO,您应该考虑让您的存储库处理此问题(通过调用.ToList()
),否则此问题代表泄漏的实现细节。
答案 2 :(得分:1)
没有ToList()
,您只返回枚举器而不是实际的对象集合。尝试访问集合时将获取实际对象。但在这种情况下,您需要的是上下文和存储库,因为您从数据库访问它们。但由于它已经超出了using
条款的范围,因此两者都被处理掉了。
答案 3 :(得分:1)
我假设ToList()深度复制对象
不完全 - 在您致电ToList
之前,您拥有的只是查询。在您枚举或通过ToList
,ToArray
,etc
将其转换为具体集合之前,您不会获得结果。
当然原始对象应该可用吗?
没有 - 它已被处理掉,这是告诉系统该对象完成其工作而不再需要的方式。您仍有未执行查询的事实不会使上下文保持可用状态。