2013-04-10 17 views
5

muszę napisać rodzajowe Search metody takie jak to:C# Generic LINQ kwerendy

public List<T> Search<T>(SearchParamsBase searchParams) 
{ 
    using (var context = new TestEntities()) 
    { 
     var dataType = TypeMap.Get(typeof (T)); 
     var dataSet = context.Set(dataType); 

     var searchQuery = CreateQuery((IEnumerable<object>) dataSet), searchParams) 

     return searchQuery.ToList() 
    } 
} 

i mam funkcję CreateQuery() które powinny filtrować IEnumerable obiekt. Ta funkcja będzie inna dla wszystkich klas. Na przykład:

CreateQuery(IEnumerable<object> collection, SearchParamsBase searchParams) 
{ 
    var search = (SomeSearchImplementation)searchParams; 
    // filter 
    collection = collection.Where(x => x.Name == search.Name); 
    // select page 
    collection = collection.Skip(search.Page * search.CountPerPage); 
    collection = collection.Take(search.CountPerPage); 
    // order by and so on 
    // ... 
    return collection; 
} 

Jak mogę poprawnie zrealizować ten pomysł?

Odpowiedz

7

Co zasadniczo chcesz zrobić, to dynamicznie konstruować zapytanie LINQ. Aby to zrobić, musisz zmodyfikować/zbudować drzewo wyrażeń w środowisku wykonawczym. Jeśli nie są zaznajomieni z drzew ekspresyjnych i rodzaj Expression<T> Polecam ten artykuł i odwołuje strony w sekcji „Zobacz także”:

http://msdn.microsoft.com/en-us/library/bb397951.aspx

Teraz, gdy już podstawowe pojęcia, niech wdrożyć dynamiczną sortowania. Poniższa metoda jest rozszerzeniem do IQueryable<T>, co oznacza, że ​​odnosi się nie tylko do list, ale do każdego źródła danych LINQ, więc można również użyć go bezpośrednio do bazy danych (która jest bardziej wydajna, jeśli chodzi o stronicowanie i sortowanie niż w operacjach pamięciowych) . Metoda przyjmuje nazwę właściwości, którą chcesz zamówić przez i kierunek sortowania (rosnąco/malejąco):

public static IQueryable<T> OrderByDynamic<T>(this IQueryable<T> query, string sortColumn, bool descending) 
{ 
    // Dynamically creates a call like this: query.OrderBy(p => p.SortColumn) 
    var parameter = Expression.Parameter(typeof(T), "p"); 

    string command = "OrderBy"; 

    if (descending) 
    { 
     command = "OrderByDescending"; 
    } 

    Expression resultExpression = null;  

    var property = typeof(T).GetProperty(sortColumn); 
    // this is the part p.SortColumn 
    var propertyAccess = Expression.MakeMemberAccess(parameter, property); 

    // this is the part p => p.SortColumn 
    var orderByExpression = Expression.Lambda(propertyAccess, parameter); 

    // finally, call the "OrderBy"/"OrderByDescending" method with the order by lamba expression 
    resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { typeof(T), property.PropertyType }, 
     query.Expression, Expression.Quote(orderByExpression)); 

    return query.Provider.CreateQuery<T>(resultExpression); 
} 

Teraz można napisać ten kod, aby zamówić zestaw danych przez obiekt Name w ascending kolejności:

dataSet.OrderByDynamic("Name", false) 

Tworzenie metody rozszerzenia dla filtrowania dynamicznego przebiega według tego samego wzorca. Jeśli rozumiesz powyższy kod, nie będzie to dla ciebie problemem.