我正在尝试动态搜索EF Core。我把整个东西做成这样的循环:
foreach (var i in vm.SearchProperties)
{
if (result == null)
result = db.MyTable.Where(x => x.GetType().GetProperty(i).GetValue(x, null).ToString().ToLower().StartsWith("MySearchString"));
else
result = result.Where(x => x.GetType().GetProperty(i).GetValue(x,null).ToString().ToLower().StartsWith(i.Suchfeld.ToLower(“mySearchString”)));
}
在我添加反射部分之前,它运行得相当快。当我将反射添加到它时,它的速度减慢了1000倍。有什么想法吗,我如何让它加速或围绕反射部分。
表达式太复杂了,LINQ to SQL转换器无法解释它,因此要对表中的每个项进行编译和执行,因此执行速度非常慢也就不足为奇了。
您需要基于要搜索的属性构建一个表达式树,然后构建一个Expression<Func<MyType, bool>>
传递给您的Where(...)
方法。这样,LINQ到SQL转换器就可以识别它。
试试这个:
ParameterExpression param = Expression.Parameter(typeof(MyType));
MethodInfo stringStartsWith = typeof(string).GetMethods().First(m => m.Name == "StartsWith" && m.GetParameters().Length == 1);
PropertyInfo firstProp = typeof(MyType).GetProperty(vm.SearchProperties.First());
MemberExpression firstMembAccess = Expression.Property(param, firstProp);
MethodCallExpression firstStartsWithExpr = Expression.Call(firstMembAccess, stringStartsWith, Expression.Constant(mySearchString));
Expression current = firstStartsWithExpr;
foreach (string s in vm.SearchProperties.Skip(1))
{
PropertyInfo prop = typeof(MyType).GetProperty(s);
MemberExpression membAccess = Expression.Property(param, prop);
MethodCallExpression startsWithExpr = Expression.Call(membAccess, stringStartsWith, Expression.Constant(mySearchString));
current = Expression.OrElse(current, startsWithExpr);
}
Expression<Func<MyType, bool>> mySearchExpression = Expression.Lambda<Func<MyType, bool>>(current, param);
result = db.MyTable.Where(mySearchExpression);
注意:MyType
指的是你的实体类型
正如人们已经回答的那样,反射不能在IQueryable中使用。
将数据加载到内存中,并执行Where子句。
类似于您执行了以下代码(在where子句之前添加ToList()):
foreach (var i in vm.SearchProperties)
{
if (result == null)
result = db.MyTable.ToList().Where(x => x.GetType().GetProperty(i).GetValue(x, null).ToString().ToLower().StartsWith("MySearchString"));
else
result = result.ToList().Where(x => x.GetType().GetProperty(i).GetValue(x,null).ToString().ToLower().StartsWith(i.Suchfeld.ToLower(“mySearchString”)));
}
@Mr Anderson是对的。你需要用表达式树代替反射。
然而,使用表达式树有时可能过于复杂而难以构建。
免责声明:我是项目Eval-Expression的所有者。净
这个项目允许你在运行时计算和执行动态表达式。
简而言之,可以将动态字符串传递给where子句。
Wiki: Eval-Expression。. NET - LINQ Dynamic
foreach (var i in vm.SearchProperties)
{
if (result == null)
result = db.MyTable.Where(x => "x." + i + ".ToLower().StartsWith('MySearchString')");
else
result = result.Where(x => "x." + i + ".ToLower().StartsWith('MySearchString')");
}