我创建了一个小型测试Web应用程序,它使用LINQ to SQL。我有ObjectDataSource和GridView。 GridView的Datasource是ObjectDataSource。现在,这个ObjectDataSource使用一个名为MyTasks的类(如下所述的方法名称:GetAllTasks())来填充SQL中使用Linq to SQL的Tasks表中的所有任务。它调用存储过程GetAllMyTasks()。
我有以下方法,它完美无缺。
public static IEnumerable<GetAllMyTasksResult> GetAllTasks()
{
MyTasksDataContext db = new MyTasksDataContext();
var tasks = db.GetAllMyTasks().Select(x => x);
return tasks;
}
现在,如果我尝试用以下代码替换上面的代码,只是为了利用关键字来创建Disposable MyTasksDataContext对象。它给我一个错误,说“读取器关闭时无效尝试调用读取”。我在这里缺少什么。
public static IEnumerable<GetAllMyTasksResult> GetAllTasks()
{
using (MyTasksDataContext db = new MyTasksDataContext())
{
var tasks = db.GetAllMyTasks().Select(x => x);
return tasks;
}
}
任何人都可以告诉我这背后的理由吗?我知道我的MyTasksDataContext对象正在调用它的dispose方法。
答案 0 :(得分:10)
使用ToList()
扩展方法尽早评估枚举。
public static IEnumerable<GetAllMyTasksResult> GetAllTasks()
{
using (MyTasksDataContext db = new MyTasksDataContext())
{
return db.GetAllMyTasks().ToList();
}
}
这将导致枚举发生在使用中,而不是在处理连接之后。
枚举需要在'using'块中发生的原因是LINQ使用了一种叫做'延迟执行'的东西,以便进行更强大的查询编写。
例如,如果您希望通用函数执行分页,则可以将.Skip(30).Take(10)
附加到结果的末尾,并且可以将该逻辑烘焙到生成的SQL中。
PS:
你说:
我知道我的MyTasksDataContext object正在调用它的dispose方法。
这是假的。
'using'块正在调用Dispose
方法,而不是对象本身。而且,由于你写了使用,你正在调用Dispose
。
答案 1 :(得分:3)
正如John Gietzen所提到的,ToList()将解决您的直接问题。
这是必要的原因是因为延迟执行。在迭代查询之前,LINQ通常不会执行任何操作。 LINQ to SQL将调用存储过程,但不会从结果中读取行,直到迭代查询。