it-swarm.com.de

LINQ To Entities erkennt die Methode Last nicht. "Ja wirklich?"

In dieser Abfrage:

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

Ich musste es auf dieses umstellen, damit es funktioniert

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

Ich konnte nicht einmal p.First() verwenden, um die erste Abfrage zu spiegeln.

Warum gibt es so grundlegende Einschränkungen in dem ansonsten so robusten ORM-System?

128
bevacqua

Diese Einschränkung beruht auf der Tatsache, dass diese Abfrage schließlich nachSQLübersetzt werden muss, und SQL hat einen SELECT TOP (in T-SQL), aber keinen SELECT BOTTOM (keine solche Sache).

Es gibt jedoch einen einfachen Weg, nur order descending und dann eine First() auszuführen, was Sie auch getan haben.

EDIT: Andere Provider werden möglicherweise andere Implementierungen von SELECT TOP 1 haben, bei Oracle wäre dies wahrscheinlich eher etwas wie WHERE ROWNUM = 1

BEARBEITEN:

Eine andere, weniger effiziente Alternative - ich empfehle das NICHT! - ruft .ToList() für Ihre Daten auf, bevor .Last() aufgerufen wird, der sofort den bis dahin aufgebauten LINQ To Entities-Ausdruck ausführt, und dann funktioniert Ihr .Last (), da an diesem Punkt .Last() effektiv ausgeführt wird stattdessen im Kontext von LINQ to Objects Expression. (Und wie Sie darauf hingewiesen haben, könnte dies Tausende von Datensätzen mit sich bringen und Lasten von CPU vergeuden, die Objekte materialisieren, die sich nie gewöhnen werden.)

Auch hier würde ich nicht empfehlen, dies zu tun, aber es macht den Unterschied, wo und wann der LINQ-Ausdruck ausgeführt wird.

199
Neil Fenwick

Anstelle von Last() versuchen Sie Folgendes:

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

Ersetzen Sie Last() durch einen Linq-Selector OrderByDescending(x => x.ID).Take(1).Single()

So etwas würde funktionieren, wenn Sie es vorziehen, es in Linq zu tun: 

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());
}
13
Ema.H

Das liegt daran, dass LINQ to Entities (und Datenbanken im Allgemeinen) nicht alle LINQ-Methoden unterstützen (Einzelheiten finden Sie hier: http://msdn.Microsoft.com/en-us/library/bb738550.aspx )

Hier müssen Sie Ihre Daten so anordnen, dass der "letzte" Datensatz "zuerst" wird und Sie dann FirstOrDefault verwenden können. Beachten Sie, dass Datenbanken normalerweise keine Begriffe wie "first" und "last" haben. Es ist nicht so, dass der zuletzt eingefügte Datensatz "last" in der Tabelle ist.

Diese Methode kann Ihr Problem lösen

db.databaseTable.OrderByDescending(obj => obj.Id).FirstOrDefault();
0
Kazem

Noch eine weitere Möglichkeit, das letzte Element ohne OrderByDescending zu erhalten und alle Entitäten zu laden:

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