我正在使用ASP.NET 4.0。
我有以下代码返回错误“无法访问已处置的对象。 对象名:'Dispose后访问的DataContext。'。“
public IEnumerable<BatchHeader> GetHeaders()
{
using(NSFChecksDataContext context = DataContext)
{
IEnumerable<BatchHeader> headers = (from h in context.BatchHeaders
select h);
return headers;
}
}
如果我将其更改为:
public IEnumerable<BatchHeader> GetHeaders()
{
using(NSFChecksDataContext context = DataContext)
{
return context.BatchHeaders.ToList();
}
}
它会正常工作。我正在使用此方法填充RadGrid。任何人都可以解释为什么第二种方法会起作用而不是第一种方法吗?
感谢。
答案 0 :(得分:16)
第一个不起作用,因为当方法返回时,using
块中实例化的数据上下文被释放。但是,返回的IEnumerable<BatchHeader>
被懒惰地评估,并且需要此数据上下文才能生成以枚举其结果。
你可以这样做:
public IEnumerable<BatchHeader> GetHeaders() {
using(NSFChecksDataContext context = DataContext) {
foreach(var header in context.BatchHeaders) {
yield return header;
}
}
}
第二个块起作用,因为在处理数据上下文之前,查询结果被枚举并存储在内存中。在那之后,不再需要数据上下文。但是,使用像第二个块一样的代码时要小心;如果BatchHeaders
表很大,你只需将它全部存入内存。
现在,这是我的答案中最严重的部分:我绝对不能忍受查看实例化数据上下文的查询。我想知道并控制何时使用我的数据上下文。
答案 1 :(得分:1)
我猜你的上下文中的IEnumerable正在使用延迟执行,所以除非你强制它使用ToList进行枚举,否则在你使用这些值之前不会这样做,在这种情况下,这些值在using块之外,所以对象将被处置。
答案 2 :(得分:-1)
return headers.AsEnumerable();
应该可以工作,因为默认情况下,linq查询返回一个IQueryable对象,这意味着在使用foreach,ToArray,ToList或AsEnumerable进行枚举之前,不会从db获取数据。当Asp.Net尝试访问IQueryable并使用foreach获取数据时,连接已经关闭。