2012-07-05 15 views
10

Korzystając z Entity Framework 4, próbuję zaimplementować dynamiczne sortowanie w oparciu o zbiór nazw członków. Zasadniczo użytkownik może wybrać pola do sortowania i kolejność sortowania. Przyjrzałem się przykładom drzewa ekspresji i nie mogę tego poskładać razem. Oto kilka szczegółów:Jak utworzyć drzewo wyrażeń do sortowania według czasu wykonywania?

Zbiór nazw kolumn:

public List<string> sortColumns; 
sortColumns = new List<string>(); 

/// Example subset of video fields. The collection will vary. 
sortColumns.Add("Width"); 
sortColumns.Add("Height"); 
sortColumns.Add("Duration"); 
sortColumns.Add("Title"); 

Klasa wideo jest zdefiniowane następująco:

public class Video 
{ 
    public string Title { get; set; } 
    public int Width { get; set; } 
    public int Height { get; set; } 
    public float Duration { get; set; } 
    public string Filename { get; set; } 
    public DateTime DateCreated { get; set; } 
    . 
    . 
    . 
} 
public List<Video> Videos; 

Co chciałbym zrobić to wyliczyć poprzez zbieranie sortColumns budowy drzewo wyrażeń w czasie wykonywania. Ponadto użytkownik może określić sortowanie rosnąco lub malejąco, a drzewo wyrażeń powinno również obsługiwać.

próbowałem biblioteki dynamicznej LINQ dla VS 2008, ale nie wydaje się, aby pracować w VS 2010. (I może być robić coś złego.)

Najważniejsze jest to, że potrzebujemy drzewa wyrażenie dynamicznie sortuj kolekcję wideo na podstawie danych wprowadzanych przez użytkownika. Każda pomoc będzie doceniona.

Odpowiedz

14

Najpierw potrzebna jest metoda rozszerzenia OrderBy, którą @Slace napisał here. Wszystkie zasługują na Slace za niesamowity kawałek kodu i zdecydowanie najtrudniejszą część rozwiązania! Wprowadziłem drobną modyfikację, aby działała w konkretnej sytuacji:

public static class QueryableExtensions 
{ 
    public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder) 
    { 
     var type = typeof(T); 
     var property = type.GetProperty(sortProperty); 
     var parameter = Expression.Parameter(type, "p"); 
     var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
     var orderByExp = Expression.Lambda(propertyAccess, parameter); 
     var typeArguments = new Type[] { type, property.PropertyType }; 
     var methodName = sortOrder == ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending"; 
     var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp)); 

     return source.Provider.CreateQuery<T>(resultExp); 
    } 
} 

Utwórz metodę sortowania listy. Kilka rzeczy zauważyć w poniższej metody:

  1. List<string> przekształca się w IQueryable<string> od czasu Enumerable operatorów nie biorą wyrażenia drzew.
  2. Do metoda iteracji listy kolumn sortowane w kolejności odwrotnej (zakładając, że chcesz dać pierwszą pozycję na liście najwyższy priorytet sortowania)

.

private void PrintVideoList(IEnumerable<string> sortColumns, ListSortDirection sortOrder) 
{ 
    var videos = this.GetVideos(); 
    var sortedVideos = videos.AsQueryable(); 

    foreach (var sortColumn in sortColumns.Reverse()) 
    { 
     sortedVideos = sortedVideos.OrderBy(sortColumn, sortOrder); 
    } 

    // Test the results 
    foreach (var video in sortedVideos) 
    { 
     Console.WriteLine(video.Title); 
    } 
} 

Następnie powinno być w stanie wykorzystać metodę tak:

// These values are entered by the user 
var sortColumns = new List<string> { "Width", "Title", "Height" }; 
var sortOrder = ListSortDirection.Ascending; 

// Print the video list base on the user selection 
this.PrintVideoList(sortColumns, sortOrder); 
+0

Można użyć już zdefiniowanego ListSortDirection (http://msdn.microsoft.com/en-us/library/system .componentmodel.listsortdirection.aspx) enum;) –

+0

@BennorMcCarthy Fantastyczny! Dzięki. Zaktualizuję odpowiedź. –

+0

'@' Kevin - Dokładnie to, czego potrzebowałem, dzięki! – James

0

jest dokładnie to, co potrzebne Kevin. Zauważyłem, że jeśli użyjesz orderby, zajmie to tylko wybór ostatniego zamówienia.

Dodałem tę metodę (ThenBy) do kopalni i wydaje się działać dobrze

public static IQueryable<T> ThenBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder) 
    { 
     var type = typeof(T); 
     var property = type.GetTypeInfo().GetDeclaredProperty(sortProperty); 
     var parameter = Expression.Parameter(type, "p"); 
     var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
     var orderByExp = Expression.Lambda(propertyAccess, parameter); 
     var typeArguments = new Type[] { type, property.PropertyType }; 
     var methodName = sortOrder == ListSortDirection.Ascending ? "ThenBy" : "ThenByDescending"; 
     var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp)); 

     return source.Provider.CreateQuery<T>(resultExp); 
    } 
Powiązane problemy