Веб сервис выглядел так:
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)