c# - mvc - LINQ To Entities no reconoce el método Last. De Verdad?
entity framework core español (4)
En esta consulta:
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());
}
Tuve que cambiarlo a esto para que funcione
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());
}
Ni siquiera p.First()
usar p.First()
, para reflejar la primera consulta.
¿Por qué existen tales limitaciones básicas en lo que de otro modo sería un sistema ORM tan robusto?
En lugar de Last()
, prueba esto:
model.OrderByDescending(o => o.Id).FirstOrDefault();
Esa limitación se reduce al hecho de que eventualmente tiene que traducir esa consulta a SQL y SQL tiene un SELECT TOP
(en T-SQL) pero no un SELECT BOTTOM
(nada de eso).
Sin embargo, hay una manera fácil de hacerlo, simplemente ordene descender y luego haga una First()
, que es lo que hizo.
EDITAR: Otros proveedores posiblemente tendrán diferentes implementaciones de SELECT TOP 1
, en Oracle probablemente sea algo más parecido a WHERE ROWNUM = 1
EDITAR:
Otra alternativa menos eficiente: ¡NO lo recomiendo! - es llamar a .ToList()
en sus datos antes de .Last()
, que ejecutará de inmediato el LINQ To Entities Expression que se ha creado hasta ese punto, y luego su .Last () funcionará, porque en ese momento el .Last()
se ejecuta efectivamente en el contexto de un LINQ to Objects Expression. (Y como usted señaló, podría traer de vuelta miles de registros y desperdiciar un montón de objetos de materialización de CPU que nunca se usarán)
De nuevo, no recomendaría hacer esto en segundo lugar, pero ayuda a ilustrar la diferencia entre dónde y cuándo se ejecuta la expresión LINQ.
Otra forma es obtener el último elemento sin OrderByDescending y cargar todas las entidades:
dbSet
.Where(f => f.Id == dbSet.Max(f2 => f2.Id))
.FirstOrDefault();
Reemplace Last()
por un selector de Linq OrderByDescending(x => x.ID).Take(1).Single()
Algo así sería trabajos si prefieres hacerlo en 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());
}