Создать Generic Expression из имени свойства строки
У меня есть переменная с именем sortColumn, которая содержит текст столбца, который я хочу отсортировать результат запроса. У меня также есть общий репозиторий, который принимает в качестве параметра выражение, которое содержит поле, которое я хочу сортировать. Кажется, я не могу получить от имени свойства строки выражение.
Итак, общий репозиторий, который у меня есть, содержит следующий метод
public IEnumerable<TEntity> Get<TOrderBy>(Expression<Func<TEntity, bool>> criteria,
Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex,
int pageSize,
bool isAssendingOrder = true,
EnumDeletePolicy deletePolicy = EnumDeletePolicy.ExcludeDeleted)
Обратите внимание на второй параметр для этого Get is Expression-Func-TEntity, TOrderBy. Как я уже упоминал, у меня есть переменная с именем sortColumn, которая содержит строку для свойства моего объекта TEntity. Мне нужно преобразовать эту строку в выражение, которое я могу передать методу Get.
Вот что я имею прямо сейчас.
var parameter = Expression.Parameter(typeof(IContract));
var memberExpression = Expression.Property(parameter, data.SortColumn);
var lambdaExpression = Expression.Lambda(memberExpression, parameter);
Что создает объект типа LambdaExpression. Фактическим типом этого выражения LambdaExpression является строка Expression-Func-IContract (или любой тип sortColumn свойства). Если я вызову метод Get и передаю это выражение LambdaExpression и явно применил его к типу Expression, тогда он будет работать нормально. Проблема в том, что я не знаю, что такое тип выражения, это может быть строка, int, int?, и т.д. Все зависит от типа свойства, определенного в свойстве sortColumn.
Можете ли вы помочь мне сделать этот последний прыжок в правильном выражении?
Изменить на основе предложений Marc:
У меня почти есть эта работа, фактически основанная конкретно на вопросе, который она работает, но у меня есть 1 проблема.
IContract, который является типом Entity, который я запрашиваю, фактически наследуется от IRelationship. Если я укажу поле из интерфейса IContract, то работает вышеописанный код. Если я укажу поле из интерфейса IRelationship, следующая строка не будет выполнена.
var memberExpression = Expression.Property(parameter, data.SortColumn);
Если я попробую что-то вроде ниже, чтобы я захватил MemberExpression из IRelationship, но построил Lambda на основе IContract, я получаю сообщение об ошибке из репозитория.
var parameter = Expression.Parameter(typeof(IRelationship));
var memberExpression = Expression.Property(parameter, data.SortColumn);
var orderBy = Expression.Lambda(memberExpression, Expression.Parameter(typeof(IContract)));
Ошибка, которую я получаю, это "Параметр" не был связан в указанном выражении запроса LINQ to Entities.
Окончательное выражение, чтобы заставить его работать, это
var parameter = Expression.Parameter(typeof(IContract));
var memberExpression = Expression.Property(parameter, typeof(IRelationship), data.SortColumn);
var orderBy = Expression.Lambda(memberExpression, parameter);
Итак, мне нужно было указать средний параметр в строке memberExpression, чтобы сказать, что в унаследованном интерфейсе отношения для свойства
Ответы
Ответ 1
Вам нужно использовать правильную общую перегрузку, что означало, что вам приходилось использовать MakeGenericMethod
; однако вы также можете использовать dynamic
, чтобы избежать необходимости использовать MakeGenericMethod
здесь, например (в данном случае через Where
, но важным моментом является то, как он работает):
IQueryable<Foo> source = new[] { new Foo { Bar = 123 } }.AsQueryable();
Expression<Func<Foo,bool>> typed = x=>x.Bar == 123;
LambdaExpression untyped = typed;
IQueryable<Foo> filtered = Queryable.Where(source, (dynamic)untyped);
Примечание. Вы не можете использовать методы расширения здесь, поэтому вам нужно использовать Queryable.*
.
Для примера OrderBy
, используя ваш код:
var parameter = Expression.Parameter(typeof(Foo));
var memberExpression = Expression.Property(parameter, "Bar");
var lambdaExpression = Expression.Lambda(memberExpression, parameter);
LambdaExpression untyped = lambdaExpression;
IQueryable<Foo> sorted = Queryable.OrderBy(source, (dynamic)untyped);
var all = sorted.ToArray();
Повторите редактирование:
var parameter = Expression.Parameter(typeof(IRelationship));
var memberExpression = Expression.Property(
Expression.Convert(parameter, typeof(IContract)), data.SortColumn);
var orderBy = Expression.Lambda(memberExpression, parameter);