我需要能够从控制器动态创建LINQ的Where
条件/过滤器。然后,我想将这些过滤器传递给存储库的方法,该方法将在使用LINQ的Where
扩展名应用动态过滤器后查询数据库。
以下是我在控制器中执行的代码,它使用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);
...
...
最后,在我的存储库中,我有这个方法,在第三个参数中使用Expression<Func<StageModel, bool>>
表达式,如果它不为空,则将其传递给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);
}
但是我在下一行收到错误
unitOfWork.Stages.GetStagesPagedList(1, PerPage, stage.Expression as MethodCallExpression)
这是错误显示的内容
错误3参数3:无法转换为&#39; System.Linq.Expressions.MethodCallExpression&#39;到&#39; System.Linq.Expressions.Expression&gt;&#39;
我也试过不像这样包装表达式 unitOfWork.Stages.GetStagesPagedList(1,PerPage,stage.Expression)
错误3参数3:无法转换 &#39; System.Linq.Expressions.Expression&#39;至 &#39;&System.Linq.Expressions.Expression GT;&#39;
如何正确进行转换?这是不可能的,我如何动态创建过滤器并将它们传递到我的存储库?
答案 0 :(得分:1)
使用假IQueryable
构建谓词不是一个好主意。当您拥有实际的Where
时,链式IQueryable
技术适用。为了构建谓词表达式,您只需要一些谓词构建器帮助程序实用程序。
例如,您可以从Establish a link between two lists in linq to entities where clause获取我自己的PredicateUtils
课程。它非常适合因为句柄null
谓词。
将类复制/粘贴到项目中,然后使用类似的内容(基本上将stage = stage.Where
替换为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);
...
...
答案 1 :(得分:0)
只需让GetStagesPagedList
接受您拥有的IQueryable
,而不是Expression
。
public IPagedList<StageModel> GetStagesPagedList(IQueryable<StageModel> stages,
int pageNumber, int pageSize)
{
return stages.OrderBy(stage => stage.Name)
.ToPagedList(pageNumber, pageSize);
}
我不知道那是否足以真正保证另一种方法,但如果你愿意,你可以自由使用它。
当您需要将IQueryable
初始化为null
时,您的调用者还有一个主要错误:
IQueryable<StageModel> stages = CastedContext.Stages;
//...
Stages = unitOfWork.Stages.GetStagesPagedList(stages, 1, PerPage);
答案 2 :(得分:0)
您需要手动创建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);