Frage

Betrachten Sie meine Event Klasse, und dass ich speichern DateTime die in der DB als UTC Termine. Ich möchte einfach einen gefilterten Bereich zurückzukehren, basierend auf dem aktuellen Datum in einer bestimmten Zeitzone - einfach rechts

Dies funktioniert:

IQueryable<Event> test1 = this.GetSortedEvents().Where(e => e.FinishDateTime.Date >= DateTime.UtcNow.Date);

Dies funktioniert auch gut:

IQueryable<Event> test2 = this.GetSortedEvents().Where(e => e.FinishDateTime.AddHours(3).Date >= DateTime.UtcNow.AddHours(3).Date);

.. und zusätzlich erfüllt meine Zeitzone Anforderungen.

Hier bin ich also denke ich diese spezifische Umwandlung aus dieser Erweiterungsmethode bewegen kann:

    public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
    {
        return utcTime.AddHours(3);
    }

Das funktioniert nicht:

IQueryable<Event> test3 = this.GetSortedEvents().Where(e => e.FinishDateTime.RiyadhTimeFromUtc().Date >= DateTime.UtcNow.RiyadhTimeFromUtc().Date);

.. und ich erhalte diese NotSupportedException. Die Methode 'System.DateTime RiyadhTimeFromUtc (System.DateTime)' hat keine unterstützte Übersetzung SQL

Das ist natürlich Quatsch, wie der Compiler glücklich, es zu SQL umgewandelt, wenn der identischen Code nicht in der Erweiterungsmethode war.

Ich habe in das „hat keine unterstützte Übersetzung zu SQL“ Problem laufen, bevor mit bestimmten Arten und zuletzt Datetime ist. Aber meine Tests oben und diesen Link beweisen, dass die AddHours Methode sein sollte in der SQL-Übersetzung unterstützt.

Wenn mir jemand sagen könnte, was ich falsch hier tun (oder eine andere Abhilfe Ansatz für dieses Problem) ich wirklich dankbar sein würde.

War es hilfreich?

Lösung

Sie haben darüber in Form eines Ausdrucksbaum denken, das ist, wie Linq-to-SQL analysiert Ihre Abfrage es in SQL zu machen.

Bei der Prüfung des Baumes ein DateTime Objekt sieht und dann prüfen, ob das Verfahren auf sie genannt eines der unterstützten Einsen (Add, AddHours, etc.) so, wenn Sie die Methode verwenden, um direkt funktioniert es gut.

Wenn Sie eine andere Erweiterungsmethode verwenden, kann es nicht innerhalb dieser Methode gehen und schauen, um zu sehen, was es tut, da die Informationen über diese Methode Körper ist nicht in dem Ausdrucksbaum, ist es in dem IL versteckt. So spielt es keine Rolle, ob der Inhalt der Erweiterungsmethode unterstützt werden, da Linq-to-SQL kann nicht herausfinden, was der Inhalt.

Der Punkt der Schaffung Methoden ist Verkapselung und Information Hiding, die in der Regel gut in der Anwendungsentwicklung funktioniert, aber leider hier es versteckt die Informationen von Linq-to-SQL, die Sie müssen in der Lage sein, die Informationen zu sehen.


Als Reaktion auf die editierte Frage - wie lösen Sie das? Wenn Sie die Datumsberechnung innerhalb der Linq Ausdruck behalten möchten, das einzige, was können Sie die Abfrage effizient zu halten tun, ist nicht eine Erweiterungsmethode zu verwenden und einfach verwenden AddHours(3) direkt am DateTime Objekt.

Es ist einer der unglücklichen Grenzen Linq. Wie viele Dinge ist es eine etwas undichte Abstraktion, die zwar gemeinsame Syntax über einen Bereich von Quellen bieten, unterschiedliche Beschränkungen und Einschränkungen hat, auf die Operationen die Anbieter für die Quelle können / werden (zum Beispiel unterstützen, würde dies in perfekt funktioniert Linq-to -Objekte wie es braucht nicht den Ausdrucksbaum zu übersetzen, um sie auszuführen).

Andere Tipps

Es scheint wie für LINQ-to-SQL, um herauszufinden, in der Lage sein, dass RiyadhTimeFromUtc war wirklich nur ein Anruf es AddHours(3) würde eine ziemlich anspruchsvolle Analyse des Codes zu tun hat. Sagen Sie schreiben:

public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
{
    if (Random.GetInt() < 99) {
       return utcTime.AddHours(3);
    } else {
       return utcTime.AddDays(5);
    }
}

Wie wäre es, das zu SQL übersetzen? Siehe dieser Diskussion für einige weitere Informationen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top