问题描述
我有一个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,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查询中结果的顺序为未定义。大多数时候,您会获得主键排序(不必与插入顺序匹配!),但是有很多事情可以改变这种情况:匹配不同的索引,将JOIN匹配到表具有不同顺序或不同索引,在同一表上与另一个查询并行执行+循环索引遍历,等等。
要解决此问题,您必须先致电OrderBy()
,然后再致电。。
再深入一点,这甚至不是SQL的一部分。这项工作正在您的客户上进行。这不好,因为表上的任何索引都不再可用。应该可以在数据库服务器上完成所有这些工作,但是选择组的第一条记录可能意味着您需要横向连接/ APPLY或row_number()窗口化功能,而这些功能很难用EF复制。要完全删除所有警告,您可能必须编写原始SQL语句:
First()
环顾四周,可以在is possible中使用EF中的row_number(),但是在这一点上,我个人觉得使用SQL更容易。我认为ORM对于这些更复杂的查询没有帮助,因为您仍然必须了解所需的SQL,并且还必须了解ORM的复杂性才能构建它。换句话说,原本可以使您的工作更轻松的工具反而使工作变得更加困难。