2010-12-29 8 views
26

Ich spiele mit FluentNHibernate und NH 3.0, mit dem LINQ-Provider und der neuen QueryOver-Syntax.NHibernate 3.0: Nein FirstOrDefault() mit QueryOver?

Jetzt mit QueryOver möchte ich einen Artikel erhalten (so genannte Ergebnis) mit einem Zeitstempel Wert so nahe wie möglich auf einen bestimmten Wert, aber nicht größer:

Result precedingOrMatchingResult = Session.QueryOver<Result>(). 
     Where(r => r.TimeStamp < timeStamp). 
     OrderBy(r => r.TimeStamp).Desc.     
     FirstOrDefault(); //get the preceding or matching result, if there is any 

Nun Intellisense sagt mir, dass es keine so etwas wie eine FirstOrDefault() Methode. Ich könnte natürlich meine geordnete Abfrage aufzählen und dann LINQ verwenden, um meinen Artikel zu bekommen. Dies würde jedoch zuerst alle Elemente in den Speicher laden.

Gibt es eine Alternative zu FirstOrDefault(), oder habe ich etwas völlig falsch verstanden?

+0

Suchen Sie nach 'SingleOrDefault()'. Bitte akzeptieren Sie die Antwort von @RRR. –

Antwort

10

NH 3 einen integrierten LINQ-Anbieter hat (Abfragen werden intern in HQL/SQL übersetzt). Sie haben die NHibernate.Linq Namespace hinzufügen und dann:

Result precedingOrMatchingResult = Session.Query<Result>(). 
    Where(r => r.TimeStamp < timeStamp). 
    OrderByDescending(r => r.TimeStamp). 
    FirstOrDefault(); 
+0

Sieht gut aus, ich werde es versuchen (nur nächstes Jahr jedoch, da ich jetzt aus bin!) – Marcel

+0

Dies macht den Trick. Da in meinen Where-Klauseln jedoch einige zusätzliche Einschränkungen bestehen, habe ich festgestellt, dass LINQ to NH die Unterstützung der .HasValue() -Methode für Nullable-Typen nicht unterstützt. Schade, aber ich überprüfe jetzt nach! = Null was funktioniert. – Marcel

+8

Dies beantwortet nicht die Frage, dies mit QueryOver zu tun. Die Antwort gilt nur für die gestellte Frage nicht. @ RRRs ist richtiger. – Jafin

9

Versuchen

Result precedingOrMatchingResult = Session.QueryOver<Result>(). 
     Where(r => r.TimeStamp < timeStamp). 
     OrderBy(r => r.TimeStamp).Desc. 
     SetFetchSize(1). 
     UniqueResult(); 

UniqueResult einen einzelnen Wert zurückgeben, oder null, wenn kein Wert gefunden wird, was irgendwie ist das, was First- oder Standard der Fall ist.

Wenn ich die Abrufgröße auf 1 setze oder nicht, würde ich das mit einem Profiler testen.

+0

Ich habe es mir angeschaut. UniqueResult scheint SingleOrDefault zu ähneln, aber ich habe kein einzelnes Element. Ich habe eine Liste, und ich möchte nur den ersten Artikel auswählen. – Marcel

+0

Was Ihre Anfrage zurückgeben soll, ist nur der erste Eintrag, richtig? Warum eine Liste vom Datenbankserver zurückgeben und dann die meiste Arbeit wegwerfen? –

35

Ich habe nun herausgefunden, dass ich die Take() Erweiterungsmethode auf der IQueryOver Instanz verwenden könnte, und nur die Aufzählung zu einer Liste, etwa so:

Result precedingOrMatchingResult = Session.QueryOver<Result>(). 
     Where(r => r.TimeStamp < timeStamp). 
     OrderBy(r => r.TimeStamp).Desc. 
     Take(1).List(). //enumerate only on element of the sequence! 
     FirstOrDefault(); //get the preceding or matching result, if there is any 
+6

Yup. 'Take' ist, was ich empfehlen würde. Kombiniere das mit RRR 'SingleOrDefault' anstelle von' List(). FirstOrDefault() 'und es ist perfekt. –

+0

Eigentlich '.Take (1)' wird das gleiche tun wie '.SetFetchSize (1)' in dem Sinne, dass es SQL sagt, dass Sie nur ein Ergebnis wollen. In beiden Fällen führen Sie keine Abfrage für alle übereinstimmenden Ergebnisse aus und führen dann eine Aufzählung über die erste aus. –

22
Result precedingOrMatchingResult = Session.QueryOver<Result>() 
              .Where(r => r.TimeStamp < timeStamp) 
              .OrderBy(r => r.TimeStamp).Desc 
              .SingleOrDefault(); 
+1

Ja, das ist die richtige Antwort. 'SingleOrDefault()' –

+3

Ursachen NHibernate.NonUniqueResultException – Graham

+0

Ich bekomme nicht eindeutige Ergebnis Ausnahme auch. –

Verwandte Themen