LINQ To Entities 无法识别方法 Last。真的吗?
Posted
技术标签:
【中文标题】LINQ To Entities 无法识别方法 Last。真的吗?【英文标题】:LINQ To Entities does not recognize the method Last. Really? 【发布时间】:2011-09-03 14:14:45 【问题描述】:在这个查询中:
public static IEnumerable<IServerOnlineCharacter> GetUpdated()
var context = DataContext.GetDataContext();
return context.ServerOnlineCharacters
.OrderBy(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName)
.Select(p => p.Last());
我必须把它切换到这个才能工作
public static IEnumerable<IServerOnlineCharacter> GetUpdated()
var context = DataContext.GetDataContext();
return context.ServerOnlineCharacters
.OrderByDescending(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName)
.Select(p => p.FirstOrDefault());
我什至无法使用p.First()
来镜像第一个查询。
为什么在如此强大的 ORM 系统中存在如此基本的限制?
【问题讨论】:
将您的 IEnumrable 对象存储到一个新变量中,然后返回 variable.last()。它会起作用的。 【参考方案1】:这种限制归结为这样一个事实,即最终它必须将该查询转换为 SQL 并且 SQL 有一个 SELECT TOP
(在 T-SQL 中)但没有一个 SELECT BOTTOM
(没有这样的东西)。
不过有一个简单的方法,只需降序,然后执行First()
,这就是您所做的。
编辑:
其他提供者可能会有不同的SELECT TOP 1
实现,在Oracle 上可能更像WHERE ROWNUM = 1
编辑:
另一个效率较低的替代方案 - 我不推荐这样做! - 是在 .Last()
之前对您的数据调用 .ToList()
,这将立即执行已构建的 LINQ To Entities 表达式到那时,您的 .Last() 将起作用,因为此时 .Last()
在 LINQ to Objects 表达式的上下文中有效执行。 (正如您所指出的,它可能会带回数千条记录并浪费大量 CPU 物化对象,这些对象永远不会被使用)
再次,我不建议这样做,但它确实有助于说明执行 LINQ 表达式的位置和时间之间的区别。
【讨论】:
LINQ To SQL 如何处理这种情况? @Neil 是的,我知道我可以调用 ToList,但我宁愿不从数据库中检索数千条记录,只是为了将它们过滤到 5 条记录 如果您知道您的查询将返回小结果,那么调用ToList
也不错。【参考方案2】:
代替Last()
,试试这个:
model.OrderByDescending(o => o.Id).FirstOrDefault();
【讨论】:
如果我使用的是泛型模型并且无法引用其中的Id
字段怎么办?
如果你的数据没有排序那么Last()
没有意义
@Schiavini 它仍然可能发生。我有一个数据库,我需要查询中的第一个和最后一个条目,但它们不能按任何字段排序,因此可以保证反转。【参考方案3】:
用 Linq 选择器 OrderByDescending(x => x.ID).Take(1).Single()
替换 Last()
如果你更喜欢在 Linq 中做类似的事情:
public static IEnumerable<IServerOnlineCharacter> GetUpdated()
var context = DataContext.GetDataContext();
return context.ServerOnlineCharacters.OrderBy(p => p.ServerStatus.ServerDateTime).GroupBy(p => p.RawName).Select(p => p.OrderByDescending(x => x.Id).Take(1).Single());
【讨论】:
有什么理由使用 .Take(1).Single() 而不是 .FirstOrDefault()? @TotZam 在这种情况下,有效的替换将是 .First(),因为如果项目计数不完全为 1,Single() 会引发异常。【参考方案4】:另一种方法是在没有 OrderByDescending 的情况下获取最后一个元素并加载所有实体:
dbSet
.Where(f => f.Id == dbSet.Max(f2 => f2.Id))
.FirstOrDefault();
【讨论】:
【参考方案5】:这是因为 LINQ to Entities(以及一般的数据库)不支持所有 LINQ 方法(详情请参阅此处:http://msdn.microsoft.com/en-us/library/bb738550.aspx)
您需要在这里对数据进行排序,使“最后一个”记录变为“第一个”,然后您可以使用 FirstOrDefault。请注意,数据库通常没有“第一”和“最后”这样的概念,它并不像最近插入的记录将是表中的“最后”。
这个方法可以解决你的问题
db.databaseTable.OrderByDescending(obj => obj.Id).FirstOrDefault();
【讨论】:
【参考方案6】:在 Select 函数对我有用之前添加一个函数 AsEnumerable()
。
示例:
return context.ServerOnlineCharacters
.OrderByDescending(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName).AsEnumerable()
.Select(p => p.FirstOrDefault());
参考: https://www.codeproject.com/Questions/1005274/LINQ-to-Entities-does-not-recognize-the-method-Sys
【讨论】:
建议将链接中的工作代码合并到您的答案中。仅链接的答案会引起负面关注。请通过添加您找到的帮助和解决问题的代码来提供完整的答案。解决了以后由于404错误导致链接失效的问题。 将示例添加到我的答案中 这个答案的缺点是它会将所有结果带到“AsEnumerable”服务器端之前,然后选择第一个。这可能是非常不可取的。 (我遇到过这样的情况,由于 20k+ 记录被带到服务器端,结果需要 20+ 秒,一旦我将它移回数据库端,结果会在不到一秒的时间内返回)以上是关于LINQ To Entities 无法识别方法 Last。真的吗?的主要内容,如果未能解决你的问题,请参考以下文章
LINQ to Entities 无法识别方法 IsNullOrWhiteSpace
错误:LINQ to Entities 无法识别方法 DataLength
LINQ To Entities 无法识别方法 Last。真的吗?
LINQ To Entities 无法识别方法 Last。真的吗?