2010-12-23 6 views
2

Ich habe eine ASP.NET MVC2 App, die stark von Rastern Gebrauch macht. Ich würde gerne sehen, ob es eine Möglichkeit gibt, effizientes Paging und Filtern zu dem typischen Spezifikationsmuster hinzuzufügen.Hinzufügen von Paging und Filtern zum typischen Linq Specification Muster?

Grundsätzlich ist der Anruf, der alles sieht wie folgt beginnt:

PatientByUserIdSpecification spc = new PatientByUserIdSpecification(userId); 
return this.patientRepository.FindAll(spc).ToList(); 

Nun, ich weiß, dass ich so etwas wie dies unten tun kann, und eine Teilmenge der Reihe als Funktion der Gittereinstellungen für das Paging erhalten und Filterung:

return this.patientRepository.FindAll(spc).OrderBy(a => a.Id).Skip(start).Take(limit).ToList(); 

Aber alle die Filterung erfolgt in der Mittelschicht, mit einem vollen Zug aller Datensätze von userId, die Hunderte von Datensätzen pro Benutzer im Laufe der Zeit wachsen kann. Dies bedeutet viel ineffiziente Netzwerk-Chattiness. Offensichtlich muss man die Kriterien so nach unten verschieben, dass das von NHibernate und Linq generierte SQL besser gefiltert wird.

Der LinqRepository Code ist im Grunde:

public IQueryable<T> FindAll(ILinqSpecification<T> specification) 
{ 
    return specification.SatisfyingElementsFrom(this.Session.Linq<T>()); 
} 

public virtual IQueryable<TResult> SatisfyingElementsFrom(IQueryable<T> candidates) 
{ 
    if (this.MatchingCriteria != null) 
    { 
     return candidates.Where(this.MatchingCriteria).ToList().ConvertAll(this.ResultMap).AsQueryable(); 
    } 

    return candidates.ToList().ConvertAll(this.ResultMap).AsQueryable(); 
} 

Und die PatientByUserIdSpecification, als Beispiel, hat die MatchingCriteria:

public override Expression<Func<Patient, bool>> MatchingCriteria 
{ 
    get { return p => p.Cases.Any(c => c.CaseUsers.Any(x => (x.User.Id == this.userId))); } 
} 

Ich dachte, dass es tun würde, die unten zu haben, aber die Abfrage ist immer noch zu breit.

Kann ich und wie kann ich die Möglichkeit einrichten, bessere SQL zu generieren?

+0

Ich weiß nicht über NHibernate aber regelmäßige Linq2SQL implementiert 'Skip()' und 'Take()' in resultierenden SQL-Abfrage. – mmix

+0

Was ist mit dem Aufruf von ToList() an Ihren Ergebnissen? Wenn Sie dies aufrufen, wird Ihre LINQ-Abfrage in SQL übersetzt und Ihre Datenbank wird abgefragt. Warum werfen Sie dann zurück auf IQueryable ? – mikesigs

Antwort

0

die Anrufe zu .ToList() in dem folgenden Code verursacht die Abfrage, bevor die LINQ Dynamische ausgeführt werden angewendet:

public virtual IQueryable<TResult> SatisfyingElementsFrom(IQueryable<T> candidates) 
{ 
    if (this.MatchingCriteria != null) 
    { 
     return candidates.Where(this.MatchingCriteria).ToList().ConvertAll(this.ResultMap).AsQueryable(); 
    } 
    return candidates.ToList().ConvertAll(this.ResultMap).AsQueryable(); 
} 

Sie Refactoring benötigen, um sie zu entfernen und das Dynamic LINQ laufen gegen das Schema der SQL-Objekte, um auf der Serverseite filtern zu können.

Verwandte Themen