LINQ To Entities ne reconnaît pas la méthode Last. Vraiment?

Dans cette requête:

public static IEnumerable GetUpdated() { var context = DataContext.GetDataContext(); return context.ServerOnlineCharacters .OrderBy(p => p.ServerStatus.ServerDateTime) .GroupBy(p => p.RawName) .Select(p => p.Last()); } 

Je devais le changer pour que ça marche

 public static IEnumerable GetUpdated() { var context = DataContext.GetDataContext(); return context.ServerOnlineCharacters .OrderByDescending(p => p.ServerStatus.ServerDateTime) .GroupBy(p => p.RawName) .Select(p => p.FirstOrDefault()); } 

Je ne pouvais même pas utiliser p.First() pour p.First() la première requête.

Pourquoi existe-t-il de telles limitations de base dans un système ORM aussi robuste?

Cette limitation se résume au fait qu’à terme, elle doit traduire cette requête en SQL et que SQL a un SELECT TOP (en T-SQL) mais pas un SELECT BOTTOM (pas une telle chose).

Il existe toutefois un moyen simple de contourner ce problème, il suffit d’ ordonner la descente puis de faire un First() , ce que vous avez fait.

EDIT: D’autres fournisseurs auront probablement des implémentations différentes de SELECT TOP 1 , sur Oracle, ce serait probablement quelque chose de plus comme WHERE ROWNUM = 1

MODIFIER:

Une autre alternative moins efficace – je ne recommande pas cela! – est d’appeler .ToList() sur vos données avant .Last() , qui exécutera immédiatement l’expression LINQ To Entities qui a été construite jusqu’à ce moment-là, puis votre fichier .Last () fonctionnera, car à ce stade le .Last() est effectivement exécuté dans le contexte d’une expression LINQ to Objects à la place. (Et comme vous l’avez souligné, cela pourrait ramener des milliers d’enregistrements et gaspiller des tonnes d’objects matérialisant des processeurs qui ne seront jamais utilisés)

Encore une fois, je ne recommanderais pas de faire cette seconde, mais cela aide à illustrer la différence entre où et quand l’expression LINQ est exécutée.

Au lieu de Last() , essayez ceci:

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

Remplacez Last() par un sélecteur Linq OrderByDescending(x => x.ID).Take(1).Single()

Quelque chose comme ça fonctionnerait si vous préférez le faire à Linq:

 public static IEnumerable 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()); } 

Une autre manière d’obtenir le dernier élément sans OrderByDescending et de charger toutes les entités:

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