C# 为什么我需要ToList()来避免已处理的上下文错误?
我正在编写一些代码来使用EntityFrameWork访问数据库。代码是:C# 为什么我需要ToList()来避免已处理的上下文错误?,c#,linq,entity-framework,asp.net-mvc-5,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
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();
}
}
public IEnumerable GetRows(int-id)
{
使用(var context=new ApplicationDbContext())
{
var repository=新EntityFrameWorkRepository(上下文);
//此处需要一个ToList()以防止发生dbcontext错误
返回repository.GetRowsFromDb(id.ToList();
}
}
GetRowsFromDb()使用LINQ查询数据库并使用id筛选结果
我最初编写上述方法时没有调用ToList(),但是当我尝试访问返回的IEnumerable中的对象时,我会得到一个关于已被释放的dbcontext的异常。我不明白上面的代码是如何解决问题的,尽管它确实可以工作。我假设ToList()正在深度复制对象,这可能提供了与上下文/数据库所需的分离,但原始对象肯定应该是可用的吗?如果不调用
。ToList()
将在using
子句完成后计算可枚举项,因此,数据上下文将在评估查询之前进行处理
IMO,您应该考虑让您的存储库处理这个问题(通过调用<代码> .TistIt()/代码>)否则,这个问题就代表了泄露的实现细节。
没有<代码> toSist](<)>代码>您只返回枚举器而不是实际的对象集合。当您尝试访问集合时,将获取实际对象。但在本例中,您需要的是上下文和存储库,因为您可以从数据库访问它们。但是,由于它已经超出了
using
子句的范围,因此这两个子句都被处理,因此出现了异常。您需要调用ToList
、ToArray
,或者枚举EF返回的数据的其他方法的原因是,LINQ中的查询执行被延迟:在显式获取数据之前不会处理数据。当您的方法返回获取查询数据的上下文时,查询数据被关闭(您的using
块会很快处理这种情况),从而导致您看到的异常
这样做是为了使代码不会花费时间处理您不需要的数据。例如,您可以编写通过客户端上的数据开始读取的代码,并在中间停止。如果查询执行没有延迟,那么您可能会花费时间和内存来获取查询的“尾部”,结果却将其丢弃。延迟执行使您处于控制之中:您可以决定在执行过程中要保留哪些数据,或者根据计划对数据执行的操作将整个集合放入内存
我假设ToList()正在深度复制对象
不完全正确-在调用ToList
之前,您所拥有的只是一个查询。只有通过ToList
、ToArray
、等将其枚举或转化为具体集合,才能得到结果
当然原始对象应该是可用的
不-它已被处理,这是您告诉系统对象已完成其工作且不再需要的方式。您仍然有一个未执行的查询这一事实并不能使上下文保持可用状态。IEnumerables
是惰性的,因此在调用方法中获取任何结果之前,将先释放上下文ToList
让事情变得急迫。搜索随机相关的“LINQ deffered execution”: