c# - 创建子查询以过滤窗口函数值
问题描述
我正在尝试将 ROW_NUMBER 功能添加到 EF Core 并通过它进行过滤。
添加自定义函数后,由于 SQL 格式错误,它可以正常工作,Select
但不能正常工作。Where
林克:
var query = dbContext.OrderItems
.Select(i => new
{
i.Name,
RowNumber = EF.Functions.RowNumber(i.ProductId)
})
.Where(i => i.RowNumber == 1);
翻译成:
SELECT
i.NAME,
ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
FROM
OrderItems AS i
WHERE
ROW_NUMBER() OVER(ORDER BY i.ProductId) = CAST(1 AS bigint)
错误:
Microsoft.Data.SqlClient.SqlException (0x80131904): Windowed functions can only appear in the SELECT or ORDER BY clauses.
要更正此 SQL,我需要创建一个子查询:
SELECT
t.NAME,
t.RowNumber
FROM (
SELECT
i.NAME,
ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
FROM
OrderItems AS i
) t
WHERE
t.RowNumber = CAST(1 AS bigint)
我在 EF Core 2 中找到了一篇关于如何执行此操作的文章。
可能,最简单的方法是引入一种方法,该方法给 EF 一个提示,即先前的查询应该是子查询。幸运的是,我们没有做太多事情,因为在内部,方法 AsQueryable(或者更确切地说与其关联的表达式)就是这样做的。
https://www.thinktecture.com/en/entity-framework-core/making-rownumber-more-useful-in-2-1/
但是这种方法在 EF Core 3.1 中没有任何作用
有没有办法创建子查询?
解决方案
查看 EF Core 3.1 源代码,我看到在应用where
过滤器之前强制子查询的唯一方法是引入查询限制(即Skip
和/或Take
)。
从两个可能的假极限运算符(Skip(0)
和Take(int.MaxValue)
)中,看起来选择后者更好,因为前者也需要一些排序(甚至是假的)。
所以解决方法是插入
.Take(int.MaxValue)
之前.Where(...)
。
生成的 SQL 并不完美(有 fakeTOP
子句),但至少是有效的。
推荐阅读
- angular - 访问在 ng-swagger-gen 中定义 api 参数的内部模块
- svg - 如何内联文本和图像
- powershell - Powershell命令在执行时出错
- python - Django模板迭代上下文列表
- reactjs - 设置状态元素后不在浏览器中呈现
- python - 基于列的熊猫排名
- c++ - c++ 函数的正确返回类型?
- python - 使用 Python readline() 通过 USB 从 Arduino Uno 获取多个传感器数据
- azure-devops - 如何在 azure devops 中触发构建和测试拉取请求?
- html - 将长文本包装到动态 div 中