从字符串属性名称创建通用表达式 [英] Create Generic Expression from string property name
问题描述
所以我包含以下方法的通用存储库
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屋!