158 votes

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

Dans cette requête:

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

Je devais le changer pour que cela fonctionne

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

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

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

242voto

Neil Points 3145

Cette limitation vient du fait que, finalement, il a à traduire cette requête SQL et SQL a un SELECT TOP (en T-SQL), mais pas un SELECT BOTTOM (pas de telle chose).

Il est un moyen facile autour d'elle si, juste l'ordre décroissant , puis faire un First(), ce qui est ce que vous avez fait.

EDIT: D'autres fournisseurs peut avoir différentes implémentations de l' SELECT TOP 1, sur l'Oracle, il serait probablement quelque chose de plus comme WHERE ROWNUM = 1

EDIT:

Une autre, moins alternative efficace - je NE recommande PAS cet! - est d'appeler .ToList() sur vos données avant d' .Last(), qui sera immédiatement exécuter le LINQ to entities Expression qui a été construit jusqu'à ce point, et alors votre .Last() va travailler, parce qu'à ce point de l' .Last() est effectivement exécuté dans le contexte d'une LINQ to Objects Expression à la place. (Et comme vous l'avez souligné, il pourrait ramener des milliers de dossiers et de déchets de charge de CPU matérialisation des objets qui ne sera jamais utilisé)

Encore une fois, je ne recommande pas de faire cette seconde, mais il ne vous aider à illustrer la différence entre où et quand l'expression LINQ est exécutée.

14voto

Ema.H Points 279

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

Quelque chose comme ça pourrait marcher si vous préférez le faire à 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());
        }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X