从字符串属性名称创建通用表达式 [英] Create Generic Expression from string property name

查看:153
本文介绍了从字符串属性名称创建通用表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为sortColumn的变量,它包含一个列,我想对查询结果进行排序。我还有一个通用存储库,它将参数包含在我要排序的字段中。我似乎不能从字符串属性名称到一个表达式。



所以我包含以下方法的通用存储库

  public IEnumerable< TEntity> Get< TOrderBy>(表达式< Func< TEntity,bool>>标准,
表达式&FunC< TEntity,TOrderBy>> orderBy,int pageIndex,
int pageSize,
bool isAssendingOrder = true,
EnumDeletePolicy deletePolicy = EnumDeletePolicy.ExcludeDeleted)

注意此Get的第二个参数是表达式 - 功能,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,string(或者该属性的sortColumn类型)。如果我调用Get方法并传入这个LambdaExpression并将其显​​式转换为Expression类型,那么它将会正常工作。问题是我不知道Expression类型是什么,它可以是一个字符串,int,int?等。这一切都取决于sortColumn属性中特定的属性的类型。



你可以帮助我最后一次跳转到表达式类型吗?



根据Marc的建议编辑:
我几乎有这个工作,实际上是基于它正在工作的问题,但我有一个剩下的问题。



IContract是我实际查询的实体类型继承自IRelationship。如果我从IContract接口指定一个字段,那么上面的代码可以工作。如果我从IRelationship界面指定一个字段,那么以下行将失败。

  var memberExpression = Expression.Property(parameter,data。 SortColumn); 

如果我尝试下面的内容,以便我从IRelationship中抓取MemberExpression,但是建立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行中指定中间参数,就是说在继承的关系界面对于属性

解决方案

您需要使用正确的通用重载 - 这意味着您必须使用 MakeGenericMethod ;但是,您也可以使用动态来避免在这里使用 MakeGenericMethod (例如通过其中,但重要的是它的工作原理):

  IQueryable< FOO> source = new [] {new Foo {Bar = 123}} .AsQueryable(); 
表达式< Func< Foo,bool>>> typed = x => x.Bar == 123;

LambdaExpression untyped = typed;
IQueryable< Foo>已过滤= Queryable.Where(源​​,(动态)无类型);

注意:您不能在这里使用扩展名方法,因此为什么需要使用 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);


I have a variable called sortColumn, which contains the text of a column that I want to sort a query result by. I also have a generic repository which takes as a parameter an Expression that contains the field I want to sort by. I can't seem to get from the string property name to an Expression.

So the generic repository that I have contains the following method

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)

Notice the second parameter to this Get is Expression-Func-TEntity, TOrderBy. As I mentioned I have a variable called sortColumn, which contains the string for a property on my TEntity object I need to convert this string into an Expression that I can pass to the Get method.

Here is what I have right now.

        var parameter = Expression.Parameter(typeof(IContract));
        var memberExpression = Expression.Property(parameter, data.SortColumn);
        var lambdaExpression = Expression.Lambda(memberExpression, parameter);

Which creates an object of type LambdaExpression. The actual type of this LambdaExpression is an Expression-Func-IContract, string (or whatever the type sortColumn of the property is). If I call the Get method and pass in this LambdaExpression and explicitly cast it to the Expression type then it will work fine. The problem is I don't know what the Expression type is, it could be a string, int, int?, etc. It all depends on the type of the property that is specific in the sortColumn property.

Can you help me make this last jump to the right Expression type?

Edit based on Marc's suggestions: I nearly have this working, actually based specifically on the question it is working, but I have 1 remaining problem.

The IContract which is the Entity Type that I'm querying against actually inherits from IRelationship. If I specify a field from the IContract interface then the code above works. If I specify a field from the IRelationship interface then the following line fails.

        var memberExpression = Expression.Property(parameter, data.SortColumn);

If I try something like below so that I'm grabbing the MemberExpression from the IRelationship, but building the Lambda based on IContract I get an error from the repository.

        var parameter = Expression.Parameter(typeof(IRelationship));
        var memberExpression = Expression.Property(parameter, data.SortColumn);
        var orderBy = Expression.Lambda(memberExpression, Expression.Parameter(typeof(IContract)));

The error that I get is "The parameter '' was not bound in the specified LINQ to Entities query expression."

The final expression to get it working was this

        var parameter = Expression.Parameter(typeof(IContract));
        var memberExpression = Expression.Property(parameter, typeof(IRelationship), data.SortColumn);
        var orderBy = Expression.Lambda(memberExpression, parameter);

So I needed to specify the middle parameter to the memberExpression line, to say look in the inherited Relationship interface for the property

解决方案

You kinda need to use the correct generic overload - which used to mean you had to use MakeGenericMethod; however, you can also use dynamic to avoid the need to use MakeGenericMethod here, for example (in this case via Where, but the important point is how it works):

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);

Note: you can't use extension methods here - hence why you need to use Queryable.*.

For an OrderBy example using your code:

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();


Re the edit:

var parameter = Expression.Parameter(typeof(IRelationship));
var memberExpression = Expression.Property(
    Expression.Convert(parameter, typeof(IContract)), data.SortColumn);
var orderBy = Expression.Lambda(memberExpression, parameter);

这篇关于从字符串属性名称创建通用表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆