W tym zapytaniu:
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());
}
Musiałem to przełączyć, aby działało
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());
}
Nie mogłem nawet użyć p.First()
, aby odzwierciedlić pierwsze zapytanie.
Dlaczego istnieją takie podstawowe ograniczenia w innym tak solidnym systemie ORM?
c#
entity-framework
orm
bevacqua
źródło
źródło
Odpowiedzi:
To ograniczenie sprowadza się do faktu, że ostatecznie musi przetłumaczyć to zapytanie na SQL, a SQL ma
SELECT TOP
(w T-SQL), ale nie maSELECT BOTTOM
(nic takiego).Jest jednak łatwy sposób na obejście tego problemu, po prostu zamów malejąco, a następnie zrób
First()
, co zrobiłeś.EDYCJA: Inni dostawcy prawdopodobnie będą mieli różne implementacje
SELECT TOP 1
, w Oracle prawdopodobnie będzie to coś bardziej podobnegoWHERE ROWNUM = 1
EDYTOWAĆ:
Kolejna mniej wydajna alternatywa - NIE POLECAM! - polega na wywołaniu
.ToList()
twoich danych wcześniej.Last()
, co natychmiast wykona wyrażenie LINQ To Entities, które zostało zbudowane do tego momentu, a następnie twoja .Last () zadziała, ponieważ w tym momencie.Last()
jest skutecznie wykonywana w kontekście Zamiast tego LINQ to Objects Expression. (I jak zauważyłeś, może to przywrócić tysiące rekordów i zmarnować mnóstwo zmaterializowanych obiektów CPU, które nigdy nie zostaną wykorzystane)Ponownie nie polecałbym robienia tego drugiego, ale pomaga to zilustrować różnicę między miejscem i czasem wykonywania wyrażenia LINQ.
źródło
ToList
nie jest takie złe.Zamiast tego
Last()
spróbuj tego:źródło
Zamień
Last()
na selektor LinqOrderByDescending(x => x.ID).Take(1).Single()
Coś takiego działałoby, gdybyś wolał zrobić to w Linq:
źródło
Jeszcze inny sposób, aby uzyskać ostatni element bez OrderByDescending i załadować wszystkie encje:
źródło
Dzieje się tak, ponieważ LINQ to Entities (i ogólnie bazy danych) nie obsługuje wszystkich metod LINQ (szczegółowe informacje można znaleźć tutaj: http://msdn.microsoft.com/en-us/library/bb738550.aspx )
Potrzebujesz tutaj uporządkować swoje dane w taki sposób, aby „ostatni” rekord stał się „pierwszy”, a następnie możesz użyć FirstOrDefault. Zauważ, że bazy danych zazwyczaj nie mają takich pojęć jak „pierwszy” i „ostatni”, to nie jest tak, że ostatnio wstawiony rekord będzie „ostatni” w tabeli.
Ta metoda może rozwiązać twój problem
źródło
Dodanie pojedynczej funkcji,
AsEnumerable()
zanim funkcja Select zadziałała dla mnie.Przykład:
Odniesienia: https://www.codeproject.com/Questions/1005274/LINQ-to-Entities-does-not-recognize-the-method-Sys
źródło