使用LINQ获取每第n行

Jul*_*Roy 5 c# linq entity-framework

我们在SQL数据库中有一个表,其中包含我需要创建图表的历史原始数据.我们通过Entity Framework和LINQ访问数据库.

对于较小的日期时间间隔,我可以简单地读取数据并生成图表:

var mydata = entity.DataLogSet.Where(dt => dt.DateTime > dateLimit);
Run Code Online (Sandbox Code Playgroud)

但我们希望实现一个功能,您可以从图表中快速"缩小"以包括更大的日期间隔(过去5天,上个月,过去6个月,过去10年等等).

我们不希望为此绘制每个数据点.我们想要使用数据样本,我的意思是这样的 -

  • 最近5天:绘制表格中的每个数据点
  • 上个月:绘制表格中每10个数据点的图表
  • 最近6个月:绘制每100个数据点的图表

数据点和图表名称的数量仅是示例.我需要的是一种从数据库中只选择"第n"行的方法.

小智 3

您可以使用包含枚举项索引的Select重载。像这样的事情应该可以解决问题——

var data = myDataLogEnumeration.
        Select((dt,i) => new { DataLog = dt, Index = i }).
        Where(x => x.Index % nth == 0).
        Select(x => x.DataLog);
Run Code Online (Sandbox Code Playgroud)

如果你需要用Where限制查询或者用OrderBy排序,你必须在第一个Select之前执行,否则索引将全部错误 -

var data = myDataLogEnumeration.
        Where(dt => dt.DateTime > dateLimit).
        OrderBy(dt => dt.SomeField).
        Select((dt,i) => new { DataLog = dt, Index = i }).
        Where(x => x.Index % nth == 0).
        Select(x => x.DataLog);
Run Code Online (Sandbox Code Playgroud)

不幸的是,正如juharr评论的那样,实体框架不支持这种重载。解决这个问题的一种方法是做这样的事情——

var data = entity.DataLogSet.
        Where(dt => dt.DateTime > dateLimit).
        OrderBy(dt => dt.SomeField).
        ToArray().
        Select((dt,i) => new { DataLog = dt, Index = i }).
        Where(x => x.Index % nth == 0).
        Select(x => x.DataLog);
Run Code Online (Sandbox Code Playgroud)

注意添加一个ToArray(). 但这并不理想,因为它会在仅选择每第 n 行之前强制加载与初始查询匹配的所有数据。

  • 我不相信 EF 支持这种重载。https://msdn.microsoft.com/en-us/library/bb738550(v=vs.110).aspx (2认同)
  • 使用 ToEnumerable() 代替 ToArray()。这样,ToEnumerable 上面的逻辑将在服务器上作为 SQL 执行,而 ToEnumerable() 下面的逻辑将在内存中执行(Linq to Objects)。由于实体框架现在默认情况下流式传输结果,因此您不必在采样之前具体化内存中的所有数据+ (2认同)