LINQ To Entities does not recognize the method Last. Really?
In this query:
public static IEnumerable<IServerOnlineCharacter> GetUpdated()
{
var context = DataContext.GetDataContext();
return context.Server开发者_如何学JAVAOnlineCharacters
.OrderBy(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName)
.Select(p => p.Last());
}
I had to switch it to this for it to work
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());
}
I couldn't even use p.First()
, to mirror the first query.
Why are there such basic limitations in what's otherwise such a robust ORM system?
That limitation comes down to the fact that eventually it has to translate that query to SQL and SQL has a SELECT TOP
(in T-SQL) but not a SELECT BOTTOM
(no such thing).
There is an easy way around it though, just order descending and then do a First()
, which is what you did.
EDIT:
Other providers will possibly have different implementations of SELECT TOP 1
, on Oracle it would probably be something more like WHERE ROWNUM = 1
EDIT:
Another less efficient alternative - I DO NOT recommend this! - is to call .ToList()
on your data before .Last()
, which will immediately execute the LINQ To Entities Expression that has been built up to that point, and then your .Last() will work, because at that point the .Last()
is effectively executed in the context of a LINQ to Objects Expression instead. (And as you pointed out, it could bring back thousands of records and waste loads of CPU materialising objects that will never get used)
Again, I would not recommend doing this second, but it does help illustrate the difference between where and when the LINQ expression is executed.
Instead of Last()
, Try this:
model.OrderByDescending(o => o.Id).FirstOrDefault();
Replace Last()
by a Linq selector OrderByDescending(x => x.ID).Take(1).Single()
Something like that would be works if you prefert do it in 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());
}
Yet another way get last element without OrderByDescending and load all entities:
dbSet
.Where(f => f.Id == dbSet.Max(f2 => f2.Id))
.FirstOrDefault();
That's because LINQ to Entities (and databases in general) does not support all the LINQ methods (see here for details: http://msdn.microsoft.com/en-us/library/bb738550.aspx)
What you need here is to order your data in such a way that the "last" record becomes "first" and then you can use FirstOrDefault. Note that databasese usually don't have such concepts as "first" and "last", it's not like the most recently inserted record will be "last" in the table.
This method can solve your problem
db.databaseTable.OrderByDescending(obj => obj.Id).FirstOrDefault();
Adding a single function AsEnumerable()
before Select function worked for me.
Example:
return context.ServerOnlineCharacters
.OrderByDescending(p => p.ServerStatus.ServerDateTime)
.GroupBy(p => p.RawName).AsEnumerable()
.Select(p => p.FirstOrDefault());
Ref: https://www.codeproject.com/Questions/1005274/LINQ-to-Entities-does-not-recognize-the-method-Sys
精彩评论