c# - 使用没有 OrderBy 和过滤器的 First/FirstOrDefault/Last/LastOrDefault 操作,这可能会导致不可预测的结果
问题描述
我有一个 linq 查询,它给了我警告,但它仍然有效。我想摆脱警告。
uses First/FirstOrDefault/Last/LastOrDefault operation without OrderBy and filter which may lead to unpredictable results.
linq 查询是
var list = (from u in _db.user
join r in _db.resource on u.userId equals r.userId
join t in _db.team on u.bossId equals t.bossId
where r.pid == pid
select new MyDto
{
pid = pid,
userId = u.userId,
teamId = t.teamId,
name = t.name
}).GroupBy(d => d.userId).Select(x => x.First()).OrderBy(y => y.userId).ToList();
我使用 EntityFramework Core 2.1
更新:
我通过评论更改了代码。
var list = (from u in _db.user
join r in _db.resource on u.userId equals r.userId
join t in _db.team on u.bossId equals t.bossId
where r.pid == pid
select new MyDto
{
pid = pid,
userId = u.userId,
teamId = t.teamId,
name = t.name
})
.GroupBy(d => d.userId)
.Select(x => x.OrderBy(y => y.userId)
.First())
.ToList();
然后有一个不同的警告。
无法翻译 LINQ 表达式 'GroupBy([user].userId, new MyDto() {pid = Convert(_8_locals1_pid_2, Int16), userId = [user].UserId, .....) 并将在本地进行评估。
解决方案
我们有这个表达
.Select(x => x.First())
哪个记录将是该表达式的第一个?没有办法知道,因为此时后面的OrderBy()
子句还没有处理。每次对相同数据运行相同查询时,您可能会得到不同的结果,具体取决于从数据库返回记录的顺序。结果是不可预测的,正如错误消息所说的那样。
但是数据库肯定会每次都以相同的顺序返回它们吗? 不,你不能这样假设。除非查询中有 ORDER BY 子句,否则不会定义SQL 查询中的结果顺序。大多数时候你会得到主键排序(它不必匹配插入顺序!),但是有很多事情可以改变这一点:匹配不同的索引,加入到具有不同顺序或不同索引的表,与同一张表上的另一个查询并行执行 + 循环索引遍历,等等。
要解决此问题,您必须先调用OrderBy()
,然后才能调用First()
。
再深入一点,这甚至不是 SQL 的一部分。这项工作正在您的客户端上进行。这不好,因为表上的任何索引都不再可用。应该可以在数据库服务器上完成所有这些工作,但选择组的第一条记录可能意味着您需要横向连接/APPLY 或 row_number() 窗口函数,这些函数很难用 EF 重现。要完全删除所有警告,您可能必须编写原始 SQL 语句:
select userId, teamId, name, pid
from (
select u.userId, t.teamId, t.name, r.pid, row_number() over (order by u.userId) rn
from User u
inner join resource r on r.userId = u.userId
inner join team t on t.bossId = u.bossId
where r.pid = @pid
) d
where d.rn = 1
环顾四周,可以在 EF 中使用 row_number(),但在这一点上,我个人发现 SQL 更易于使用。我的观点是 ORM 对这些更复杂的查询没有帮助,因为你仍然必须知道你想要的 SQL,并且你还必须知道 ORM 的复杂性才能构建它。换句话说,本应让你的工作更轻松的工具反而变得更难了。
推荐阅读
- android - 修饰符“const”不适用于“局部变量”,为什么?
- c# - EF Core Entity 层构造函数的含义
- python - 如何在 STREAMLIT 中指定要保存的上传文件的确切文件夹?
- gpu - 如何用一个 GPU 启动 n 个任务?
- javascript - 如何使用具有离子和角度的照片相机在firebase中同时保存多个图像
- pandoc - 自定义 Pandoc 编写器元素输出
- nginx - 如何阻止 Nginx 上的攻击,如下面的代码?
- django - 使用文件实例 DRF、Vue.js 3 更新条目
- c# - 如何将字符串中的值转换为 C# 中的 System.Windows.Point?
- javascript - 在总值中添加或减去多个元素的值