实体框架中的Row_number(由yyy分区)

时间:2015-10-13 09:00:23

标签: sql entity-framework window-functions

我想通过使用EF在Rowition上加载数据。

    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();

1 个答案:

答案 0 :(得分:9)

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

修改 :因为您需要对行号进行过滤,但看起来不支持接受Select的{​​{1}}方法(以及作为Linq To Entity中的Expression<Func<T,int,TResult>>方法。我不认为这是构建表达式树的问题,这意味着即使手动构建它,它仍然不会被支持。我认为您可以使用一些解决方法,您仍然可以使用ZipSkip来过滤所需的行。

以下代码将仅过滤每个组中的第一行(相当于条件Take):

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的1个值进行过滤,因此GoodsID不需要将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(); Skip的想法。