使用AsEnumerable()对分页有什么影响?

时间:2012-05-12 21:55:21

标签: c# linq linq-to-sql linq-to-objects asenumerable

据我所知,如果linq查询中有一些函数没有映射到sql查询,那么你必须首先调用.AsEnumerable():

var model = _service.GetQuery
                    .Where(data => data.SomeFlag == true)
                    .Select(data => new { Foo = CalculateFoo(data.Bar); });

不能由linq执行到sql,但是通过添加AsEnumerable(),我们可以使.select()子句由linq执行到对象:

var model = _service.GetQuery
                    .Where(data => data.SomeFlag == true)
                    .AsEnumerable()
                    .Select(data => new { Foo = CalculateFoo(data.Bar); });

但是,如果数据集非常大,那么AsEnumerable对分页有什么影响呢?如果我说:

var page = model.Skip((page > 0 ? page - 1 : 0) * rows).Take(rows);

因为model现在是IEnumerable而不是IQueryable,当我们说model.Skip()。Take()时,它是否必须首先从数据库加载整个数据集才能跳过并取走? (这会破坏传呼的目的)

编辑:这个问题一般是写的 - 这些都是具体的细节:

我无法控制分页。我正在生成一个模型并将其传递给网格组件(在这种情况下为DevExpress,但可以是任何网格)。发出分页命令的是网格组件。涉及使用.Skip()的任何解决方案。在此之前无法使用AsEnumerable()之前的Take()。

所以我需要能够将此模型传递给网格,同时确保模型使用延迟执行:

var model = _service.GetQuery
                .Where(data => data.SomeFlag == true)
                .Select(data => new {
                     data.Id,
                     data.Customer.Code,
                     data.Customer.Name,
                     // etc, select a few other properties 
                     Foo = CalculateFoo(data.Bar);
                });

所以现在我有一个摇滚与硬地问题:

  • 如果我将该模型传递给网格,则在显示当前页面时会抛出异常,因为linq to sql无法执行CalculateFoo()
  • 如果我添加AsEnumerable(),那么网格可以显示当前页面,但它必须加载整个数据集才能这样做(加载数千行只显示其中的200行)
  • 如果我将Foo列从模型中删除,那么我们会再次推迟执行,但网格缺少列

2 个答案:

答案 0 :(得分:1)

只需在Skip/Take之前致电AsEnumerable()

var model = _service.GetQuery
                    .Where(data => data.SomeFlag == true)
                    .Skip((page > 0 ? page - 1 : 0) * rows).Take(rows)
                    .AsEnumerable()
                    .Select(data => new { Foo = CalculateFoo(data.Bar); });

答案 1 :(得分:1)

如果您进行分页,则需要...页面和总计

所以

var query= _service.GetQuery
                    .Where(data => data.SomeFlag == true);

ViewBag.Total = query.Count();
var model = query.Skip((page > 0 ? page - 1 : 0) * rows).Take(rows)
                    .AsEnumerable()
                    .Select(data => new { Foo = CalculateFoo(data.Bar); });

因为模型现在是IEnumerable而不是IQueryable,当我们说model.Skip()。Take()时,是否必须首先从数据库加载整个数据集才能跳过并取走? (这会破坏传呼的目的)

这是一个事实:在“分页”之前,你将始终只有你的“被linq2entites接受”的查询。

修改

我无法控制分页。我正在生成一个模型并将其传递给网格组件(在这种情况下为DevExpress,但可以是任何网格)。发出分页命令的是网格组件。任何涉及使用.Skip()的解决方案。在此之前无法使用AsEnumerable()之前的Take()。

嗯,“通常”网格系统允许(telerik)(或只有(MvcContrib)自定义分页(这意味着你必须提供“选定页面”结果+总数,如我的答案)。

我在“DevExpress自定义分页”上进行了搜索(你可以更进一步),结果很少。不知道他们是否对你有意思。

回答的例子

http://www.devexpress.com/Support/Center/p/Q264453.aspx

http://community.devexpress.com/forums/p/98848/338135.aspx