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());
}
J'ai dû le changer pour que ça marche
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 y a-t-il des limitations de base dans ce qui est autrement un système ORM aussi robuste?
c#
entity-framework
orm
bevacqua
la source
la source
Réponses:
Cette limitation se résume au fait qu'il doit finalement traduire cette requête en SQL et SQL a un
SELECT TOP
(en T-SQL) mais pas unSELECT BOTTOM
(rien de tel).Il existe cependant un moyen simple de contourner le problème, il suffit de commander en ordre décroissant , puis de faire un
First()
, ce que vous avez fait.EDIT: D'autres fournisseurs auront éventuellement des implémentations différentes de
SELECT TOP 1
, sur Oracle, ce serait probablement quelque chose de plus commeWHERE ROWNUM = 1
ÉDITER:
Une autre alternative moins efficace - je ne recommande PAS cela! - consiste à appeler
.ToList()
vos données avant.Last()
, ce qui exécutera immédiatement l'expression LINQ To Entities qui a été construite jusqu'à ce point, puis votre .Last () fonctionnera, car à ce stade, le.Last()
est effectivement exécuté dans le contexte d'un LINQ to Objects Expression à la place. (Et comme vous l'avez souligné, cela pourrait ramener des milliers d'enregistrements et gaspiller des charges d'objets matérialisant le processeur 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.
la source
ToList
n'est pas si mal.Au lieu de
Last()
, essayez ceci:la source
Remplacer
Last()
par un sélecteur LinqOrderByDescending(x => x.ID).Take(1).Single()
Quelque chose comme ça fonctionnerait si vous préférez le faire dans Linq:
la source
Encore une autre façon d'obtenir le dernier élément sans OrderByDescending et de charger toutes les entités:
la source
C'est parce que LINQ to Entities (et les bases de données en général) ne prend pas en charge toutes les méthodes LINQ (voir ici pour plus de détails: http://msdn.microsoft.com/en-us/library/bb738550.aspx )
Ce dont vous avez besoin ici, c'est d'ordonner vos données de manière à ce que le "dernier" enregistrement devienne le "premier" et vous pouvez ensuite utiliser FirstOrDefault. Notez que les bases de données n'ont généralement pas de concepts tels que "premier" et "dernier", ce n'est pas comme si l'enregistrement le plus récemment inséré sera "dernier" dans le tableau.
Cette méthode peut résoudre votre problème
la source
L'ajout d'une seule fonction
AsEnumerable()
avant la fonction Select a fonctionné pour moi.Exemple:
Réf: https://www.codeproject.com/Questions/1005274/LINQ-to-Entities-does-not-recognize-the-method-Sys
la source