use*_*867 6 c# linq linq-to-entities
我有一个相当复杂的linq to entity查询,我在网站上显示.它使用分页,所以我从来没有一次下载超过50条记录进行显示.
但我也想让用户选择将完整结果导出到Excel或其他一些文件格式.
我担心的是,一次可能会有大量的记录被加载到内存中来执行此操作.
有没有办法一次处理linq结果集1记录,就像你可以使用datareader一样,所以一次只能在内存中保存1条记录?
我已经看到了一些建议,如果你使用foreach循环对linq查询进行枚举,那么记录不会立即被读入内存并且不会过度使用服务器.
有没有人有我可以阅读的内容链接来验证这一点?
我很感激任何帮助.
谢谢
设置ObjectContext为MergeOption.NoTracking(因为它是只读操作).如果您使用相同的方法ObjectContext来保存其他数据,请从上下文中分离对象.
怎么分开
foreach( IQueryable)
{
//do something
objectContext.Detach(object);
}
Run Code Online (Sandbox Code Playgroud)
编辑:如果您使用NoTracking选项,则无需分离
EDIT2:我写信给马特·沃伦有关此方案.在他的批准下,我在这里发布相关的私人通信
SQL服务器的结果可能甚至都不是由服务器生成的.查询已在服务器上启动,第一批结果将传输到客户端,但在客户端请求继续读取之前不会再生成(或者它们缓存在服务器上).这就是所谓的'firehose cursor'模式,有时也称为流式传输.服务器正在尽可能快地发送它们,并且客户端正在尽可能快地读取它们(您的代码),但是下面有一个数据传输协议,需要客户端确认继续发送更多数据.
由于IQueryable继承自IEnumerable,我相信发送到服务器的基础查询将是相同的.但是,当我们执行a时IEnumerable.ToList(),底层连接使用的数据读取器将开始填充对象,对象将加载到app域中,并且可能会耗尽内存,这些对象无法处理.
当您使用foreach并且IEunmerable数据读取器一次读取一个SQL结果集时,将创建对象并进行处理.底层连接可能以块的形式接收数据,并且在读取所有块之前可能不会向SQL Server发送响应.因此,您不会遇到"内存不足"异常
编辑3:
当您的查询正在运行时,您实际上可以打开SQL Server"活动监视器"并查看查询,任务状态为SUSPENDED,等待类型为Async_network_IO- 实际上表明结果在SQL Server网络缓冲区中.你可以在这里和这里阅读更多相关信息