Веб сервис выглядел так:
public List<Student> GetStudents() { var query = (from student in db.Students select new { student.StudentID, student.LastName, student.FirstName, ... } ... }
Потом добавилось требования сортировать грид по нажатию на шапку колонки. Данные о сортируемой колонке должны были передаваться в сервис:
public List<Student> GetStudents(string column, bool asc)
и тут стал вопрос "а как ?", если у меня анонимный тип. Это потом я уже собираю в Student:
Вариант в лоб:
if (!asc) { switch(column) { case "FirstName": query = query.OrderByDescending(p => p.FirstName); break; case "LastName": query = query.OrderByDescending(p => p.LastName); break; ... ... // All columns } } else { switch(column) { case "FirstName": query = query.OrderBy(p => p.FirstName); break; case "LastName": query = query.OrderBy(p => p.LastName); break; ... ... // All columns } }
Что, не? Та да... :)
Второй вариант и наверно единственный (если вы не мазохист) - это использовать LINQ Expressions. Что оно такое и как работает читайте в msdn или на блогах. Я напишу свое решение относительно моих требований и условий. В результате получится:
query = query.OrderBy(column, asc);
Для того чтоб все казалось как "так и надо" я использовал Extension Methods, которые появились в .NET 3.0.
public static class OrderByExtension { /// <summary>Orders the sequence by specific column and direction.</summary> /// <param name="query">The query.</param> /// <param name="sortColumn">The sort column.</param> /// <param name="ascending">if set to true [ascending].</param> public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string sortColumn, string direction) { string methodName = string.Format("OrderBy{0}", direction.ToLower() == "ascending" ? "" : direction); // .OrderBy{Direction}(p => p.{ColumnName}) PropertyInfo property = query.ElementType.GetProperty(sortColumn); ParameterExpression parameter = Expression.Parameter(query.ElementType, "p"); MemberExpression paramAccess = Expression.MakeMemberAccess(parameter, property); LambdaExpression orderByLambda = Expression.Lambda(paramAccess, parameter); MethodCallExpression result = Expression.Call( typeof(Queryable), methodName, new[] { query.ElementType, property.PropertyType }, query.Expression, Expression.Quote(orderByLambda)); return query.Provider.CreateQuery<T>(result); } }
В общем виде формирование запроса разбивается на следующие этапы:
- Определяем метод сортировки OrderBy или OrderByDescending.
- Получить ссылку на поле, которое участвует в результирующей выборке.
- Далее формируем lambda выражение: p => p.[ColumnName], где в [ColumnName] будет подставлено поле, которое мы получили в пункте 2.
- Создаем вызов метода OrderBy например, который использует labda из пункта 3.: OrderBy(p => p.[ColumnName])
- Внедряем наш метод в цепочку вызовов: return query.Provider.CreateQuery(result)
Комментариев нет:
Отправить комментарий