Ich spiele mit den Ausdrucksbäumen herum und versuche, ihre Funktionsweise besser zu verstehen. Ich habe ein paar Beispielcodes geschrieben, mit denen ich arbeite und hoffe, dass mir jemand helfen kann.
Ich habe also diese etwas chaotische Anfrage:
/// <summary>
/// Retrieves the total number of messages for the user.
/// </summary>
/// <param name="username">The name of the user.</param>
/// <param name="sent">True if retrieving the number of messages sent.</param>
/// <returns>The total number of messages.</returns>
public int GetMessageCountBy_Username(string username, bool sent)
{
var query = _dataContext.Messages
.Where(x => (sent ? x.Sender.ToLower() : x.Recipient.ToLower()) == username.ToLower())
.Count();
return query;
}
_dataContext
ist der Datenkontext des Entity Frameworks. Diese Abfrage funktioniert wunderbar, aber sie ist nicht einfach zu lesen. Ich habe beschlossen, die Inline-IF-Anweisung in eine Func
wie diese:
public int GetMessageCountBy_Username(string username, bool sent)
{
Func<Message, string> userSelector = x => sent ? x.Sender : x.Recipient;
var query = _dataContext.Messages
.Where(x => userSelector(x).ToLower() == username.ToLower())
.Count();
return query;
}
Das scheint gut zu funktionieren, aber es gibt ein Problem. Denn die Abfrage ist gegen IQueryable<T>
Dieser LINQ-Ausdruck wird in SQL übersetzt, um in der Datenquelle ausgeführt zu werden. Das ist großartig, aber deshalb weiß es nicht, was es mit dem Aufruf von userSelector(x)
und löst eine Ausnahme aus. Es kann diesen Delegaten nicht in einen Ausdruck übersetzen.
Nun, da ich verstehe, warum es nicht funktioniert, möchte ich versuchen, es zum Laufen zu bringen. Es ist viel mehr Arbeit für das, was ich brauche, aber ich tue es nur aus reinem Interesse. Wie könnte ich das drehen Func
in einen Ausdruck, der in SQL übersetzt werden kann?
Ich habe versucht, dies zu tun:
Expression<Func<Message, string>> userSelectorExpression = x => sent ? x.Sender : x.Recipient;
Func<Message, string> userSelector = userSelectorExpression.Compile();
Dabei erhalte ich jedoch den gleichen Fehler. Ich glaube, ich bin nicht zu verstehen, Ausdrücke. Ich glaube, alles, was ich mit dem obigen Code mache, ist, einen Ausdruck zu schreiben, ihn dann aber wieder in ausführbaren Code umzuwandeln und dann denselben Fehler zu bekommen. Wenn ich jedoch versuche, Folgendes zu verwenden userSelectorExpression
innerhalb der LINQ-Abfrage kann sie nicht wie eine Methode aufgerufen werden.
Modifier
Für diejenigen, die sich für die Ausnahme interessieren, hier ist sie:
Der LINQ-Ausdrucksknotentyp "Invoke" wird in LINQ to Entities nicht unterstützt.
Ich habe das so verstanden, dass es nicht die userSelector
Delegierte. Denn, wie oben erwähnt, muss er sie in einen Ausdrucksbaum übersetzen.
Wenn Sie eine echte Methode verwenden, erhalten Sie eine etwas ausführlichere Fehlermeldung:
LINQ to Entities erkennt die Methode 'System.String userSelector(Message, Boolean)' nicht, und diese Methode kann nicht in einen Speicherausdruck übersetzt werden.