Row_number 在 Entity Framework 中超过(按 yyy 划分)
Row_number over (Partition by yyy) in Entity Framework
我想通过 Row_number 使用 EF 通过分区加载数据。
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
这个查询是我的期望。
我尝试使用这个表达式,但不幸的是 ef 无法识别 Zip 扩展方法
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 条记录table。
**已编辑
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 查询,我认为您需要首先根据 PARTITION BY
子句中的内容对它们进行分组,然后按日期对每组进行排序。然后投影每个组以包含每个条目及其索引。然后 SelectMany
将所有组展平,然后应用过滤器,最后投影出你想要的结果。可以看到我们根本不需要所谓的Zip
。
Edit:因为您需要过滤行号但看起来像 Select
方法接受 Expression<Func<T,int,TResult>>
不受支持(以及 Linq To Entity 中的 Zip
方法)。我不认为这是构建表达式树的问题,意味着即使手动构建它,它仍然不会被支持。我认为您可以使用一些解决方法,您仍然可以使用 Skip
和 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
仅筛选 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();
我希望你理解使用 Skip
和 Take
的想法,以适用于各种情况。
我想通过 Row_number 使用 EF 通过分区加载数据。
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
这个查询是我的期望。
我尝试使用这个表达式,但不幸的是 ef 无法识别 Zip 扩展方法
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 条记录table。
**已编辑
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 查询,我认为您需要首先根据 PARTITION BY
子句中的内容对它们进行分组,然后按日期对每组进行排序。然后投影每个组以包含每个条目及其索引。然后 SelectMany
将所有组展平,然后应用过滤器,最后投影出你想要的结果。可以看到我们根本不需要所谓的Zip
。
Edit:因为您需要过滤行号但看起来像 Select
方法接受 Expression<Func<T,int,TResult>>
不受支持(以及 Linq To Entity 中的 Zip
方法)。我不认为这是构建表达式树的问题,意味着即使手动构建它,它仍然不会被支持。我认为您可以使用一些解决方法,您仍然可以使用 Skip
和 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
仅筛选 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();
我希望你理解使用 Skip
和 Take
的想法,以适用于各种情况。