2012-11-21 8 views
8

Ich habe eine Reporting-Schnittstelle, wo der Endbenutzer mehrere Felder für die Sortierreihenfolge des zurückgegebenen Berichts auswählen. Das Problem, das ich habe, ist, dass ich die OrderBy/ThenBy-Methoden nicht wirklich verketten kann, da ich eine Liste von Sortierfeldern durchlaufe. Ich denke, so etwas wie dieses:Programmatisch Kette OrderBy/ThenBy mit LINQ/Entity Framework

foreach (string sort in data.SortParams) 
{ 
    switch (sort) 
    { 
     case "state": 
      query = query.ThenBy(l => l.RegionCode); 
      break; 
     case "type": 
      query = query.ThenBy(l => l.Type); 
      break; 
     case "color": 
      query = query.ThenBy(l => l.Color); 
      break; 
     case "category": 
      query = query.OrderBy(l => l.Category); 
      break; 
    } 
} 

(Anmerkung:. Ich den Schalter entfernt haben zu bestimmen, ob dies die erste Art Artikel willen der Einfachheit halber ist)

Irgendwelche Gedanken auf, wie durch eine Sammlung iterieren um die Sortierreihenfolge zu bestimmen?

Antwort

15

Sie können tun, was Sie wollen, wenn Sie einen ersten „Samen“ OrderBy verwenden:

EDIT Sie brauchen OrderBy rufen eine IOrderedEnumerable (oder IOrderedQueryable) zuerst zu erstellen, bevor ThenBy Klauseln Befestigung:

var orderedQuery = query.OrderBy(l => 0); 
foreach (string sort in data.SortParams) 
{ 
    switch (sort) 
    { 
     case "state": 
      orderedQuery = orderedQuery.ThenBy(l => l.RegionCode); 
      break; 
     case "type": 
      orderedQuery = orderedQuery.ThenBy(l => l.Type); 
      break; 
     case "color": 
      orderedQuery = orderedQuery.ThenBy(l => l.Color); 
      break; 
     case "category": 
      orderedQuery = orderedQuery.ThenBy(l => l.Category); 
      break; 
    } 
} 
query = orderedQuery; // cast back to original type. 

Wenn Sie etwas flexibler Check-out this answer

+0

Creative, muss jedoch prüfen, ob sich dies auf die Abfrageleistung auswirkt. Es könnte die Indexnutzung verhindern. – usr

+1

Das funktionierte wie ein Zauber für mich. Zuerst hatte ich genau den gleichen Code wie oben, aber ich war gezwungen, eine Standardspalte für das erste 'OrderBy()' zu wählen - ich wusste nicht, dass ich stattdessen dort 0 setzen könnte. Die 0 führt dazu, dass die ultimative SQL-Abfrage mit einer zusätzlichen Spalte mit dem Wert 0 für jede Zeile ausgegeben wird. Anschließend wird nach dieser Zeile sortiert, um die Dummy-Sortierung zu erreichen. Anschließend werden alle Spalten in den verketteten 'ThenBy() 'übernommen 'dass du hinzugefügt hast. Vielen Dank! – BeemerGuy

+0

Ich erhalte 'ArgumentOutOfRangeException' beim Aufruf von' OrderBy (l => 0) '. [Hier] (https://pastebin.com/raw/TZQ9g8Es) ist der 'StackTrace'. – Shimmy

-1

Kann alles in einem sein Linq Abfrage ist nicht die beste Option aus Sicht der Lesbarkeit. Ich würde IQueryable verwenden, um Ihre Abfrage im Speicher zu erstellen. Verwenden Sie eine ähnliche Art von switch-Anweisung (aber mit IQueryable), und führen Sie dann am Ende .ToList (d. H. Enumerieren) aus, um die gewünschte Abfrage auf dem Server auszuführen.

+1

Danke, aber die 'query' var hier ist in der Tat ein IQueryable; Das Problem tritt mit den Befehlen OrderBy und ThenBy auf. Es scheint, als ob ThenBy nur verwendet werden kann, wenn es zuerst an eine OrderBy angekettet ist. – acullen72

+1

Sorgen Sie dafür, dass Sie über die Abstimmung abstimmen !! ???????? – daehaai

1

ich diese Erweiterung erstellt haben Methoden ein identisches Problem zu lösen, wie in der Frage angegeben:

public static class QueryableExtensions 
{ 
    public static IOrderedQueryable<T> AppendOrderBy<T, TKey>(this IQueryable<T> query, Expression<Func<T, TKey>> keySelector) 
     => query.Expression.Type == typeof(IOrderedQueryable<T>) 
     ? ((IOrderedQueryable<T>) query).ThenBy(keySelector) 
     : query.OrderBy(keySelector); 

    public static IOrderedQueryable<T> AppendOrderByDescending<T, TKey>(this IQueryable<T> query, Expression<Func<T, TKey>> keySelector) 
     => query.Expression.Type == typeof(IOrderedQueryable<T>) 
      ? ((IOrderedQueryable<T>)query).ThenByDescending(keySelector) 
      : query.OrderByDescending(keySelector); 
} 

Der Code in der Frage dann Refactoring werden:

nur
foreach (string sort in data.SortParams) 
{ 
    switch (sort) 
    { 
     case "state": 
      query = query.AppendOrderBy(l => l.RegionCode); 
      break; 
     case "type": 
      query = query.AppendOrderBy(l => l.Type); 
      break; 
     case "color": 
      query = query.AppendOrderBy(l => l.Color); 
      break; 
     case "category": 
      query = query.AppendOrderBy(l => l.Category); 
      break; 
    } 
} 

REMARK Diese Erweiterung Methoden, um den vorherigen Ausdrucks in der Check Ausdruck Baum zu bestimmen, ob OrderBy oder ThenBy zu verwenden, keine anderen Ausdrücke sind dazwischen erlaubt. Wenn Sie das auch angehen wollen, müssen Sie durch den kompletten Baum gehen, der nur den Overhead hinzufügen könnte, den Sie nicht wollen :)