Я пытаюсь добавить orderby выражение на лету. Но когда запрос ниже выполняется, я получаю следующее исключение:
Система. NotSupportedException: Не удалось создать постоянную стоимость типа 'Тип закрытия'. Только типы примитивов ('такие как Int32, Строка и Гуид') поддерживаются в этом контексте.
Странная вещь, я - запрос точно те типы примитивов только.
string sortBy = HttpContext.Current.Request.QueryString["sidx"];
ParameterExpression prm = Expression.Parameter(typeof(buskerPosting), "posting");
Expression orderByProperty = Expression.Property(prm, sortBy);
// get the paged records
IQueryable<PostingListItemDto> query =
(from posting in be.buskerPosting
where posting.buskerAccount.cmsMember.nodeId == m.Id
orderby orderByProperty
//orderby posting.Created
select new PostingListItemDto { Set = posting }).Skip<PostingListItemDto>((page - 1) * pageSize).Take<PostingListItemDto>(pageSize);
Надежда кто-то может пролить некоторый свет на это!
Вы не можете использовать подобные выражения запроса из-за способа их перевода. Однако вы можете сделать это явно с помощью методов расширения:
string sortBy = HttpContext.Current.Request.QueryString["sidx"];
ParameterExpression prm = Expression.Parameter(typeof(buskerPosting), "posting");
Expression orderByProperty = Expression.Property(prm, sortBy);
// get the paged records
IQueryable<PostingListItemDto> query = be.buskerPosting
.Where(posting => posting.buskerAccount.cmsMember.nodeId == m.Id)
.OrderBy(orderByExpression)
.Select(posting => new PostingListItemDto { Set = posting })
.Skip<PostingListItemDto>((page - 1) * pageSize)
.Take<PostingListItemDto>(pageSize);
Сложная задача - получить правильный тип дерева выражений - это будет при редактировании :)
РЕДАКТИРОВАТЬ: Редактирование будет несколько задерживается по разным причинам. В основном вам может потребоваться вызвать общий метод с использованием отражения, поскольку Queryable.OrderBy
требует общего Expression
, и хотя похоже, что вы знаете ] source во время компиляции, вы можете не знать тип ключа. Если вы действительно знаете, что он всегда будет упорядочивать (скажем) по int, вы можете использовать:
Expression orderByProperty = Expression.Property(prm, sortBy);
var orderByExpression = Expression.Lambda<Func<buskerPosting, int>>
(orderByProperty, new[] { prm });
РЕДАКТИРОВАТЬ: Хорошо, похоже, у меня все-таки было время.Вот краткий пример вызова OrderBy
с использованием отражения:
using System;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
string[] names = { "Jon", "Holly", "Tom", "Robin", "Will" };
var query = names.AsQueryable();
query = CallOrderBy(query, "Length");
foreach (var name in query)
{
Console.WriteLine(name);
}
}
private static readonly MethodInfo OrderByMethod =
typeof(Queryable).GetMethods()
.Where(method => method.Name == "OrderBy")
.Where(method => method.GetParameters().Length == 2)
.Single();
public static IQueryable<TSource> CallOrderBy<TSource>
(IQueryable<TSource> source, string propertyName)
{
ParameterExpression parameter = Expression.Parameter(typeof(TSource), "posting");
Expression orderByProperty = Expression.Property(parameter, propertyName);
LambdaExpression lambda = Expression.Lambda(orderByProperty, new[] { parameter });
Console.WriteLine(lambda);
MethodInfo genericMethod = OrderByMethod.MakeGenericMethod
(new[] { typeof(TSource), orderByProperty.Type });
object ret = genericMethod.Invoke(null, new object[] {source, lambda});
return (IQueryable<TSource>) ret;
}
}
Вы можете легко преобразовать CallOrderBy
в метод расширения (например, OrderByProperty
) следующим образом:
public static class ReflectionQueryable
{
private static readonly MethodInfo OrderByMethod =
typeof(Queryable).GetMethods()
.Where(method => method.Name == "OrderBy")
.Where(method => method.GetParameters().Length == 2)
.Single();
public static IQueryable<TSource> OrderByProperty<TSource>
(this IQueryable<TSource> source, string propertyName)
{
ParameterExpression parameter = Expression.Parameter(typeof(TSource), "posting");
Expression orderByProperty = Expression.Property(parameter, propertyName);
LambdaExpression lambda = Expression.Lambda(orderByProperty, new[] { parameter });
Console.WriteLine(lambda);
MethodInfo genericMethod = OrderByMethod.MakeGenericMethod
(new[] { typeof(TSource), orderByProperty.Type });
object ret = genericMethod.Invoke(null, new object[] {source, lambda});
return (IQueryable<TSource>) ret;
}
}
Ваш исходный код будет выглядеть следующим образом:
string sortBy = HttpContext.Current.Request.QueryString["sidx"];
// get the paged records
IQueryable<PostingListItemDto> query = be.buskerPosting
.Where(posting => posting.buskerAccount.cmsMember.nodeId == m.Id)
.OrderByProperty(sortBy)
.Select(posting => new PostingListItemDto { Set = posting })
.Skip<PostingListItemDto>((page - 1) * pageSize)
.Take<PostingListItemDto>(pageSize);
(Извинения за форматирование с использованием горизонтальных полос прокрутки ... Я переформатирую позже, если кому-то будет интересно. Или вы можете сделать это за меня, если у вас достаточно репутации;)
{{1} }