【问题标题】:Row_number over (Partition by yyy) in Entity Framework实体框架中的 Row_number over(按 yyy 分区)
【发布时间】:2016-01-10 22:47:29
【问题描述】:

我想使用 EF 按 Row_number 在 Partition 上加载数据。

    SELECT *
    FROM (
       SELECT sf.SerialFlowsId
                     ,sf.GoodsSerialId
                     ,d.FormTypeId
                     , d.GoodsId
                     ,ROW_NUMBER() OVER (PARTITION BY d.GoodsId, sf.GoodsSerialId ORDER BY sf.Date DESC)row
       FROM sam.SerialFlows sf
       INNER JOIN sam.Detail d ON d.DetailId = sf.DetailId
       )z
WHERE z.row =1 
       AND z.FormTypeId=7
       AND z.GoodsId=51532

这个查询是我的期望。

我尝试使用此表达式,但不幸的是 Zip 扩展方法无法在 ef 中识别

var goodsSerials = context.SerialFlows.OrderByDescending(x => x.Date).GroupBy(x => new { x.Detail.GoodsID, x.Date })
                    .Select(g => new {g})
                    .SelectMany(z => z.g.Select(c => c)).Zip(m, (j, i) => new { GoodSerial=j,j.Detail.FormTypeID,j.Detail.GoodsID,rn=i })
                    .Where(x => x.rn== 1 && x.GoodsID== goodsId && x.FormTypeID==7).Select(x => x.GoodSerial).ToList();

我在 SerialFlows 表中有超过 20000000 条记录。

**已编辑

  var goodsSerials = context.SerialFlows
                                          .Where(e => e.Detail.GoodsID == goodsId )
                                          .GroupBy(x => x.GoodsSerialID)
                                          .Select(g => g.OrderByDescending(e=>e.Date).Take(1))
                                          .SelectMany(e => e.Where(x=>x.Detail.FormTypeID==7).Select(z=>z.GoodsSerial)).ToList();

*** 由该查询解决

        var goodsSerials = context.SerialFlows
                                          .Include(x => x.Detail)
                                          .Where(e => e.Detail.GoodsID == goodsId)
                                          .GroupBy(x => x.GoodsSerialID)
                                          .Select(g => g.OrderByDescending(e => e.Date).Take(1).Where(x=>x.Detail.FormTypeID==7))
                                          .SelectMany(e => e.Select(z => z.GoodsSerial)).ToList();

【问题讨论】:

  • 为什么投反对票?对我来说似乎是一个非常好的问题。

标签: sql entity-framework window-functions


【解决方案1】:

从您的 SQL 查询中,我认为您需要首先按 PARTITION BY 子句中的内容对它们进行分组,然后按日期对每个组进行排序。然后投影每个组以包含每个条目及其索引。然后SelectMany 将所有组展平,然后应用过滤器,最后投影您想要的结果。你可以看到我们根本不需要所谓的Zip

编辑:因为您需要过滤行号,但看起来不支持接受 Expression<Func<T,int,TResult>>Select 方法(以及 @987654326 @Linq To Entity 中的方法)。我不认为这是构建表达式树的问题,这意味着即使手动构建它,它仍然不受支持。我认为您可以使用一些解决方法,您仍然可以使用 SkipTake 过滤您想要的行。

以下代码将只过滤每组中的第一行(相当于条件rn == 1):

var goodsSerials = context.SerialFlows
                          .Where(e => e.Detail.GoodsID == goodsId &&
                                      e.Detail.FormTypeID == 7)
                          .GroupBy(x => new { x.Detail.GoodsID, x.GoodsSerialId })
                          .Select(g => g.OrderByDescending(e => e.Date)
                                        .Take(1))
                          .SelectMany(e => e).ToList();

Where 仅过滤 GoodsID 的 1 个值,因此 GroupBy 不需要将 GoodsID 包含在键中,因此它会更简单,如下所示:

var goodsSerials = context.SerialFlows
                          .Where(e => e.Detail.GoodsID == goodsId &&
                                      e.Detail.FormTypeID == 7)
                          .GroupBy(x => x.GoodsSerialId)
                          .Select(g => g.OrderByDescending(e => e.Date).Take(1))
                          .SelectMany(e => e).ToList();

希望你理解使用SkipTake 应用于各种情况的想法。

【讨论】:

  • 不幸的是我遇到了错误。附加信息:LINQ to Entities 无法识别方法 'System.Collections.Generic.IEnumerable
  • @MahdiFarhani 看到我的编辑,看起来我们几乎无法提取行号,但为了过滤,我们有一个很好的解决方法。
  • 已运行,但性能无法接受。耗时 4 多分钟,我已取消。
  • 我在sql server中运行EF生成的SQL查询,耗时14分钟,结果为空。
  • @MahdiFarhani 我对您的原始查询视而不见,我认为可以更简单地完成,请尝试编辑后的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多