2009-07-22 4 views
2

Ich habe in den letzten Monaten eine Webapp mit Linq zu NHibernate entwickelt, aber habe das SQL, das es generiert, bis jetzt nicht profiliert. Bei Verwendung von NH Profiler scheint der folgende Codeabschnitt die Datenbank mehr als 3.000 Mal zu erreichen, wenn der Linq-Ausdruck ausgeführt wird.Linq zu NHibernate generiert 3.000 + SQL-Anweisungen in einer Anfrage!

 var activeCaseList = from c in UserRepository.GetCasesByProjectManagerID(consultantId) 
          where c.CompletionDate == null 
          select new { c.PropertyID, c.Reference, c.Property.Address, DaysOld = DateTime.Now.Subtract(c.CreationDate).Days, JobValue = String.Format("£{0:0,0}", c.JobValue), c.CurrentStatus }; 

Wenn das Repository-Methode wie folgt aussieht:

public IEnumerable<Case> GetCasesByProjectManagerID(int projectManagerId) 
    { 
     return from c in Session.Linq<Case>() 
       where c.ProjectManagerID == projectManagerId 
       select c; 
    } 

Es erscheint zuerst die anfängliche Repository Abfrage auszuführen, durchläuft dann alle Ergebnisse zu überprüfen, ob die CompletionDate null ist, sondern eine Ausstellung Abfrage, um c.Property.Address zuerst zu erhalten.

Wenn also die anfängliche Abfrage 2000 Datensätze zurückgibt, auch wenn nur fünf von ihnen kein CompletionDate haben, löst sie immer noch eine SQL-Abfrage aus, um die Adressendetails für die 2000 Datensätze zurückzuholen.

Die Art, wie ich dies vorgestellt hatte funktionieren würde, ist, dass es sie alle der WHERE und SELECT-Klauseln und einfach fusionieren, so dass die inital Abfrage wäre wie beurteilen würde:

SELECT ... WHERE Projectmanager = @ p1 AND CompleteDate ist NICHT NULL

Das würde 5 Datensätze ergeben, und dann könnte es die weiteren 5 Abfragen auslösen, um die Adressen zu erhalten. Erwarte ich hier zu viel oder mache ich einfach etwas falsch?

Anthony

Antwort

6

Ändern Sie die Deklaration von GetCasesByProjectManagerID:

public IQueryable<Case> GetCasesByProjectManagerID(int projectManagerId) 

Sie können keine Abfragen mit IEnumerable<T> zusammenstellen - sie sind nur Sequenzen. IQueryable<T> ist speziell für eine solche Zusammensetzung konzipiert.

+0

Prost, das ist viel besser! – littlecharva

0

Da kann ich noch keinen Kommentar hinzufügen. Jon Skeet hat recht, wenn Sie IQueryable verwenden möchten, dies ermöglicht es dem Linq-Provider, die SQL-Datenbank zu erstellen. IEnumerable ist die eifrige Version.