[英]How can I convert IQueryable expression object into LINQ expression?
I need to be able to create LINQ's Where
conditions/filters dynamically from a controller. 我需要能够创建LINQ的
Where
条件/动态地从一个控制器过滤器。 Then, I want to pass these filters to a repository's method that will query the database after applying the dynamic filters using LINQ's Where
extension. 然后,我想将这些过滤器传递给存储库的方法,该方法将在使用LINQ的
Where
扩展应用动态过滤器后查询数据库。
Here is the code that I execute in my controller which dynamically creates filters using the IQueryable
object 这是我在控制器中执行的代码,该代码使用
IQueryable
对象动态创建过滤器
IQueryable<StageModel> stage = null;
if(model.ClientId != null)
{
stage = stage.Where(s => s.ClientId == model.ClientId);
}
if (model.CategoryIds != null && model.CategoryIds.Any())
{
var stageIds = new List<int>{ 1, 2, 3 }; // this will be dynamically generated
stage = stage.Where(s => stageIds.Contains(s.Id));
}
Stages = unitOfWork.Stages.GetStagesPagedList(1, PerPage, stage.Expression as MethodCallExpression);
...
...
Finally, in my repository I have this method that takes Expression<Func<StageModel, bool>>
expression in the third argument and passes it to the Where
extension if it isn't null. 最后,在我的存储库中,我有一个方法,该方法在第三个参数中使用
Expression<Func<StageModel, bool>>
表达式,如果不为null,则将其传递给Where
扩展。
public IPagedList<StageModel> GetStagesPagedList(int pageNumber, int pageSize, Expression<Func<StageModel, bool>> predicate = null)
{
IQueryable<StageModel> stages = CastedContext.Stages;
if (predicate != null)
{
stages = stages.Where(predicate);
}
return stages.OrderBy(stage => stage.Name)
.ToPagedList(pageNumber, pageSize);
}
But I am getting an error on the following line 但是我在下一行出现错误
unitOfWork.Stages.GetStagesPagedList(1, PerPage, stage.Expression as MethodCallExpression)
This is what the error shows 这是错误所显示的
Error 3 Argument 3: cannot convert from 'System.Linq.Expressions.MethodCallExpression' to 'System.Linq.Expressions.Expression>'
错误3参数3:无法从“ System.Linq.Expressions.MethodCallExpression”转换为“ System.Linq.Expressions.Expression>”
I also tried not casing the expression like so unitOfWork.Stages.GetStagesPagedList(1, PerPage, stage.Expression) 我也试过不使用像unitOfWork.Stages.GetStagesPagedList(1,PerPage,stage.Expression)这样的表达式
Error 3 Argument 3: cannot convert from 'System.Linq.Expressions.Expression' to 'System.Linq.Expressions.Expression>'
错误3参数3:无法从'System.Linq.Expressions.Expression'转换为'System.Linq.Expressions.Expression>'
How can I correctly do the conversion? 如何正确进行转换? Is this isn't possible, how can I dynamically create filters and pass them to my repository?
这是不可能的,如何动态创建过滤器并将其传递到我的存储库?
Using fake IQueryable
to build predicate is not a good idea. 使用伪造的
IQueryable
构建谓词不是一个好主意。 The chained Where
technique is applicable when you have the actual IQueryable
. 当您拥有实际的
IQueryable
时,适用链式Where
技术。 In order to build predicate expression, all you need is some predicate builder helper utility. 为了构建谓词表达式,您需要的是一些谓词生成器帮助器实用程序。
For instance, you can take my own PredicateUtils
class from Establish a link between two lists in linq to entities where clause . 例如,您可以从建立linq中两个列表之间的链接到实体where子句中获取我自己的
PredicateUtils
类。 It perfectly fits because handles null
predicates. 它非常适合,因为处理
null
谓词。
Copy/paste the class to your project, then use something like this (basically replace stage = stage.Where
with predicate = predicate.And
): 将类复制/粘贴到您的项目中,然后使用类似的东西(基本上替换
stage = stage.Where
with predicate = predicate.And
):
var predicate = PredicateUtils.Null<StageModel>();
if(model.ClientId != null)
{
predicate = predicate.And(s => s.ClientId == model.ClientId);
}
if (model.CategoryIds != null && model.CategoryIds.Any())
{
var stageIds = new List<int>{ 1, 2, 3 }; // this will be dynamically generated
predicate = predicate.And(s => stageIds.Contains(s.Id));
}
Stages = unitOfWork.Stages.GetStagesPagedList(1, PerPage, predicate);
...
...
Simply have GetStagesPagedList
accept the IQueryable
that you have, rather than an Expression
. 只需让
GetStagesPagedList
接受您拥有的IQueryable
,而不是Expression
。
public IPagedList<StageModel> GetStagesPagedList(IQueryable<StageModel> stages,
int pageNumber, int pageSize)
{
return stages.OrderBy(stage => stage.Name)
.ToPagedList(pageNumber, pageSize);
}
I don't know that that's doing enough to really warrant another method, but you're free to use it if you want. 我不知道这样做是否足以保证使用另一种方法,但是您可以随意使用它。
Also your caller has a major bug in that you initialize the IQueryable
to null
, when you need to initialize it to the data context's table: 同样,您的调用方还有一个主要的错误,那就是当您需要将
IQueryable
初始化为null
时,需要将其初始化为数据上下文的表:
IQueryable<StageModel> stages = CastedContext.Stages;
//...
Stages = unitOfWork.Stages.GetStagesPagedList(stages, 1, PerPage);
You need to manually create an Expression
like this: 您需要手动创建一个
Expression
如下所示:
var parameter = Expression.Parameter(typeof(StagedModel), "s");
Expression stage = null;
if (model.ClientId != null)
{
stage = Expression.Equal(Expression.PropertyOrField(parameter, "ClientId"), Expression.Constant(model.ClientId));
}
if (model.CategoryIds != null && model.CategoryIds.Any())
{
var stageIds = new List<int> { 1, 2, 3 };
Expression contains = null;
foreach (var id in stageIds)
{
var equals = Expression.Equal(Expression.Constant(id), Expression.PropertyOrField(parameter, "Id"));
contains = contains == null ? equals : Expression.OrElse(contains, equals);
}
stage = stage == null ? stage : Expression.AndAlso(stage, contains);
}
var lambda = Expression.Lambda<Func<StagedModel, bool>>(stage, parameter);
Stages = unitOfWork.Stages.GetStagesPagedList(1, PerPage, stage);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.