[英]Dynamic lambda expression doesn't work in LINQ to EF Where function
我正在尝试在asp.net mvc中完成一个页面以过滤sql server视图。 我的页面如下所示:
每个“过滤器”都是一个SearchViewModel
,它具有如下的类定义:
public class SearchViewModel
{
//Property has a property called "SqlColumnName"
public Property Property { get; set; }
public Enums.SearchOperator Operator { get; set; }
public string Value { get; set; }
}
当我提交表单时, IList<SearchViewModel>
将被传递给控制器。 到这里为止,一切正常。
在控制器类中,我将IList<SearchViewModel>
传递给辅助方法:
public static Func<ViewEvents, bool> GetLamdaExpression(IEnumerable<SearchViewModel> lstSearchViewModels)
{
Expression dynamiclambda = null;
Expression call;
//creating the first part of the lambda expression (select.Where(ve => ve.Name == "exp"))
// this function returns "(ve =>" as typeof ViewEvents
var param = Expression.Parameter(typeof(ViewEvents), "viewEvents");
//storing functions for use with the combiner
var containsMethod = typeof(string).GetMethod("Contains");
var equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) });
var startsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var endsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
var toLowerMethod = typeof(string).GetMethod("ToLower", Type.EmptyTypes);
foreach (var lstSearchViewModel in lstSearchViewModels.Where(svm => svm.Value != null))
{
//get the property info of the property from the SearchViewModel
var property = typeof(ViewEvents).GetProperty(lstSearchViewModel.Property.SqlColumnName);
if (property == null)
throw new ObjectNotFoundException($"The object {typeof(ViewEvents).ToString()} does not have a property called {lstSearchViewModel.Property.SqlColumnName}");
//create the second part of the lambda expression
//this function returns "ve.Property"
var propertyAccess = Expression.MakeMemberAccess(param, property);
//add the "toLower" function to the property
//this function returns "(ve.Property.ToLower()"
var toLower = Expression.Call(propertyAccess, toLowerMethod);
//adds the operator to the lambda expression
//functions return p.ex.: ve.Property.ToLower().Contains("value")
// or ve.Property.ToLower().Equals("value") != true (NotEquals)
switch (lstSearchViewModel.Operator)
{
case Enums.SearchOperator.Contains:
call = Expression.Call(toLower, containsMethod,
Expression.Constant(lstSearchViewModel.Value.ToLower()));
break;
case Enums.SearchOperator.ContainsNot:
call = Expression.Call(toLower, containsMethod,
Expression.Constant(lstSearchViewModel.Value.ToLower()));
//adding ..Contains("value") != true ; used like .ContainsNot("value")
call = Expression.NotEqual(call, Expression.Constant(true));
break;
case Enums.SearchOperator.StartsWith:
call = Expression.Call(toLower, startsWithMethod,
Expression.Constant(lstSearchViewModel.Value.ToLower()));
break;
case Enums.SearchOperator.EndsWith:
call = Expression.Call(toLower, endsWithMethod,
Expression.Constant(lstSearchViewModel.Value.ToLower()));
break;
case Enums.SearchOperator.Equals:
call = Expression.Call(toLower, equalsMethod,
Expression.Constant(lstSearchViewModel.Value.ToLower()));
break;
case Enums.SearchOperator.EqualsNot:
call = Expression.Call(toLower, equalsMethod,
Expression.Constant(lstSearchViewModel.Value.ToLower()));
//adding ..Equals("value") != true ; used like .NotEquals("value")
call = Expression.NotEqual(call, Expression.Constant(true));
break;
default:
throw new ArgumentOutOfRangeException();
}
//Combind the filters with an and combiner
dynamiclambda = dynamiclambda == null ? call : Expression.And(dynamiclambda, call);
}
if (dynamiclambda == null)
{
throw new InvalidOperationException("No dynamiclambda was created");
}
//gets the actual lambda expression like: (ve => ve.Property.ToLower().Contains("value") AND ve.Property.ToLower().Equals("value") ...
var predicate = Expression.Lambda<Func<ViewEvents, bool>>(dynamiclambda, param);
var compiled = predicate.Compile();
return compiled;
}
现在,当我在“ Typ”旁边的输入字段中输入值“ 1”时,该函数的变量predicate
包含以下值:
{viewEvents => viewEvents.Level.ToLower().Contains("1")}
稍后在控制器中,将使用编译后的谓词通过实体框架6查询数据库的视图,如下所示:
var lambda = Helper.GetLamdaExpression(lstSearchViewModels);
var eventEntries = DataBase.ViewEvents.Where(lambda);
这就是“错误”。 没有从数据库返回任何行。 但是当我将代码更改为
var lambda = Helper.GetLamdaExpression(lstSearchViewModels);
var eventEntries = DataBase.ViewEvents.Where(viewEvents => viewEvents.Level.ToLower().Contains("1"));
返回预期的行数。
任何人都知道错误在哪里吗?
问题是您必须使用Expression<Func<>>
而不是Func<>
。 第一个包含一个表达式树,可以对其进行解析以将Where
子句转换为SQL。 后者无法做到。
除了您过于繁琐之外:您可以直接返回lambda,而无需做太多工作。 这是一个简化的示例:
public Expression<Func<ViewEvents, bool>> GetEqualIdLambda(int id)
{
return (ViewEvents ve) => ve.Id == id;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.