LINQ To Entities无法识别方法Last。真?


144

在此查询中:

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()。它会工作。
Ali.Rashidi

Answers:


220

这种局限性归结为这样一个事实,即最终它必须将该查询转换为SQL,而SQL具有SELECT TOP(在T-SQL中)但没有SELECT BOTTOM(没有这种东西)。

不过,有一种简单的方法,只需对降序进行排序,然后执行First(),这就是您所做的。

编辑: 其他提供程序可能会有的不同实现SELECT TOP 1,在Oracle上可能更像WHERE ROWNUM = 1

编辑:

另一种效率较低的替代方法- 我不建议这样做!-是.ToList()在之前调用您的数据.Last(),它将立即执行到那时为止已建立的LINQ To Entities Expression,然后您的.Last()将起作用,因为在那一点上,.Last().Last()有效地执行了改为LINQ to Objects Expression。(正如您所指出的那样,它可能会带回成千上万的记录并浪费CPU实体化的对象,这些对象将永远不会被使用)

再次,我不建议您再进行此操作,但这确实有助于说明执行LINQ表达式的位置和时间之间的差异。


LINQ To SQL如何处理这种情况?
bevacqua 2011年

@Neil是的,我知道我可以调用ToList,但是我不想从数据库中检索成千上万条记录,只是为了将它们过滤为5条记录
bevacqua 2011年

2
如果您知道查询将返回较小的结果,则调用ToList还不错。
贾斯汀·斯基尔斯

35

代替Last(),试试这个:

model.OrderByDescending(o => o.Id).FirstOrDefault();

14

Last()Linq选择器替换OrderByDescending(x => x.ID).Take(1).Single()

如果您更喜欢在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());
}

1
是否有任何理由使用.Take(1).Single()而不是.FirstOrDefault()?
Tot Zam

2
@TotZam有效的替代将是。首先()在这种情况下,由于单()抛出一个异常,如果项目数不完全是1
MEMark

0

另一种方法是获取没有OrderByDescending的最后一个元素并加载所有实体:

dbSet
    .Where(f => f.Id == dbSet.Max(f2 => f2.Id))
    .FirstOrDefault();

0

这是因为LINQ to Entities(通常是数据库)不支持所有LINQ方法(有关详细信息,请参见此处:http : //msdn.microsoft.com/zh-cn/library/bb738550.aspx

这里需要的是对数据进行排序,以使“最后”记录变为“第一”,然后可以使用FirstOrDefault。请注意,databasese通常没有诸如“ first”和“ last”之类的概念,这与表中最近插入的记录不是“ last”一样。

这种方法可以解决你的问题

db.databaseTable.OrderByDescending(obj => obj.Id).FirstOrDefault();

-2

AsEnumerable()在Select函数对我有用之前,添加一个函数。
例:

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错误而导致链接无法正常工作的问题。
Studocwho

1
在我的答案中添加了示例
Artem Levitin

这个答案的缺点是它将所有结果带到“ AsEnumerable”服务器端之前,然后选择第一个。这可能是非常不希望的。(我遇到这样的情况,由于20k +记录被带到服务器端,结果花费了20+秒,一旦我将其移回DB端,结果在不到一秒钟的时间内返回)
TChadwick
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.