2011-01-16 9 views
1

Ich habe eine Abfrage:IEnumerable vs IQueryable

topics.OrderBy(x => x.Replies.Any() ? x.Replies.OrderBy(y => y.PostedDate).Last().PostedDate : x.PostedDate); 

Es sortiert die Sammlung Themen von letzter Antwort, oder wenn es keine Antwort hat dann durch sein eigenes Postdatum. Es funktioniert gut und macht seine Arbeit gut. Es funktioniert jedoch nur, wenn Themen vom Typ IEnumerable<Topic> sind. Wenn ich versuche, es "IQueryable" zu machen, erhalte ich einen Fehler, der besagt, dass die Erweiterungsmethode Last() unbekannt ist oder etwas zu diesem Zweck.

Wer weiß warum? Aus irgendeinem Grund erhalten x.Replies.Last() innerhalb dieser Abfrage, während Themen IQueryable diese Ausnahme auslöst.

Ich möchte, dass Themen IQQueryable sein, weil ich zuerst Themen mit allen Themen aus der Datenbank laden, sortiert nach letzter Antwort. Ich mache dann .Skip() und .Take() auf Themen für Paging. Zur Zeit werden jedoch ALLE Themen in den Speicher gezogen und dann die .Skip() und .Take() für die In-Memory-Sammlung ausgeführt. Das ist inakzeptabel, denn je mehr Themen dem Forum hinzugefügt werden, desto länger dauert das Laden der Site, insbesondere wenn die Datenbank nicht auf demselben Computer wie die Website ausgeführt wird. Ich brauche die Datenbank nur die ausgelagerten Zeilen, nicht alle Zeilen. Ich möchte, dass das Paging auf Datenbankebene erfolgt.

Irgendwelche Ideen?

PS - Ich bin mit LINQ to Entities mit Entity Framework 4.0

Antwort

3

Haben Sie versucht topics.OrderBy(x => x.Replies.Any() ? x.Replies.Max(y => y.PostedDate) : x.PostedDate);?

+0

Das war genau das, was ich brauchte. Es wurde schön in einen Speicherausdruck übersetzt, der mit IQueryable verwendet und an EF für Abfragen auf niedriger Ebene gesendet wird. Woo hoo! – Chev

1

Sind Sie Zusammenhang mit der Datenbank noch aktiv, wenn Sie versuchen, den Code, den Sie geschrieben laufen? Wenn Sie (oder .NET) den Datenbankkontext entfernt haben, können Sie nicht mehr auf die Daten im IQueryable-Objekt zugreifen, da die Verbindung verloren gegangen ist.

/Viktor

+0

Diese Abfrage Teil einer Erweiterungsmethode SQL OrderByLastReply genannt wird. Würde der Kontext dort verloren gehen? Wenn ja, kann der Kontext in einer Erweiterungsmethode beibehalten werden? – Chev

+0

Das hängt sehr davon ab, wie der Code aussieht. Wenn Sie ein Objekt vom Typ IQueryable haben, wird es nicht ausgeführt, bis es benötigt wird. Wenn Sie also eine using-Anweisung mit Ihrem Datenbankkontext haben, müssen Sie sicherstellen, dass die Abfrage innerhalb dieser Anweisung ausgeführt wird und Sie nur das IQueryable-Objekt zurückgeben Dies wird nicht passieren und Sie erhalten eine Ausnahme, wenn Sie versuchen, die Abfrage auszuführen.Es kann auf viele Arten gemacht werden, aber der einfache Weg besteht darin, einfach .ToList() für das Objekt aufzurufen und die Liste zurückzugeben. Meine Vermutung für Sie ist, dass Sie Ihren Auslagerungscode näher an die Datenbankabfrage verschieben müssen. – Viktor

+0

Sie haben Recht. Ich verwende das Repository-Muster. Das Repository gibt IQueryable zurück und der Controller führt das Paging durch. Ich werde das Paging in eine neue Methode im Repository verschieben, die das Paging durchführt und IEnumerable zurückgibt, so dass ich mich nicht um Abfragesachen im Controller kümmern muss. Ich werde dich wissen lassen, wie es sich entwickelt. – Chev

0

Ich denke, EF nicht in der Lage ist, Ihre Abfrage korrekt zu übersetzen, passiert es. Da es nicht notwendig ist, dass jede lamda erfolgreich in esql konvertiert, hat sie ihre eigenen Beschränkungen. Ich denke, es ist sehr komplizierte SQL-Abfrage für was Sie suchen.

Ich schlage vor, dass Sie ein neues DateTime-Feld in Ihren Themen erstellen können, das als "LastUpdate" bezeichnet wird und standardmäßig zum PostDate von Topic wird, wenn es erstellt wird. Zweitens, wenn Sie eine neue Antwort hinzufügen, stellen Sie sicher, dass Sie auch das LastUpdate von Topic aktualisieren.

Indem Sie dies tun, machen Sie auch Ihre Abfrage sehr einfach, und vermeiden Sie unnötige Verbindung beim Erstellen Ihrer Abfrage. Sie müssen nicht nach PostDate der Antworttabelle mit einem Join suchen.

Ich mache diese Art von Caching (die Bezeichnung der Denormierung in Datenbank Design genannt), das ist nicht in Bezug auf das Design perfekt, aber durch Leistung und Codierung, ist es viel einfacher und einfacher.

+0

Ja, ich habe gehofft, das zu vermeiden. Zum einen brauche ich das letzte Antwortdatum UND den letzten Antwortautor. Wenn die letzte Antwort gelöscht wird, möchte ich, dass die Sortierung sich selbst repariert und das Thema an die ursprüngliche Position zurückversetzt. Mit dem zusätzlichen Feld würde das Thema ohne neue Antworten bleiben. – Chev

+0

Ja ich stimme zu, aber wenn Sie in Bezug auf die Leistung denken, lesen Sie Zeile der Tabelle 99 mal und Sie nur einmal ändern, mit EF sollte es nicht so schwierig sein, wenn Sie Ihre Antwort löschen, müssen Sie zusätzliche Logik hinzufügen Die Details zu den Antworten der Antwort. Ich habe festgestellt, erhöhte Leistung mit Caching, glaube mir, ob wir es mögen oder nicht, auch in der CPU haben Sie Cache, IE hat temporäre Dateien, überall Cache funktioniert besser. –

1

IEnumerable: LINQ zu Object und LINQ zu XML.

IQueryable: LINQ

+2

Was soll das heißen? – BoltClock

Verwandte Themen