反射的性能问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射的性能问题相关的知识,希望对你有一定的参考价值。
我正在尝试动态搜索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 to 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.NET项目的所有者
该项目允许您在运行时评估和执行动态表达式。
简而言之,您可以将动态字符串传递给where子句。
维基: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')");
}
以上是关于反射的性能问题的主要内容,如果未能解决你的问题,请参考以下文章