用变量的常量动态生成lambda表达式 [英] Dynamically generate lambda expression with constants from variables
问题描述
我已经解决了一些异常的问题,一些EF 6代码,即使在2ms内执行底层查询时,与Oracle.ManagedDataAccess.Client驱动程序一起运行的查询有时也需要几分钟的时间才能返回结果。一个示例查询将如下所示:
I've been troubleshooting an unusual issue with some EF 6 code where queries running with the Oracle.ManagedDataAccess.Client driver are sometimes taking several minutes to return results even when the underlying query executes within 2ms. An example query would be as follows:
var result = users.Where(u => u.username == varUserName).FirstOrDefault();
此查询可能需要几分钟的时间才能返回,但是如果将查询与相同的内容替换为在lambda函数中不变,它会立即运行:
This query might take several minutes to return, however if I replace the query with the same thing with a constant in the lambda function, it runs instantaneously:
var result = users.Where(u => u.username == "testUsername").FirstOrDefault();
要解决此问题,我可以编写参数化的SQL查询,也可以手动生成适当的lambda表达式树:
To work around this issue, I can either write parameterised SQL queries, or I can manually generate an appropriate lambda expression tree:
var userParam = Expression.Parameter(typeof(Entity.User), "user");
var userNameField = Expression.Property(userParam, "username");
var userNameConstant = Expression.Constant(varUserName, typeof(string));
var equalUserName = Expression.Equal(userNameField, userNameConstant);
var lambda = Expression.Lambda<Func<Entity.User, bool>>(equalUserName, new ParameterExpression[] { userParam });
var result = users.Where(lambda).FirstOrDefault();
因为这样做,它提出了一个问题:有一种方法可以轻松地生成lambda表达式导致变量直接包含在常量中的树,而不是引用变量?
Because this works, it begs the question: is there a way to easily generate lambda expression trees which result in variables being directly included as constants, instead of references to variables?
例如,这样的东西是理想的:
For example, something like this would be ideal:
var lambdaExpression = (u => u.username == varUserName).ReplaceVariablesWithConstants();
推荐答案
可以使用 ExpressionVisitor
它评估 ConstantExpression
这样的成员:
It can be done relatively easy with ExpressionVisitor
which evaluates the ConstantExpression
members like this:
public static class ExpressionUtils
{
public static Expression<TDelegate> ReplaceVariablesWithConstants<TDelegate>(this Expression<TDelegate> source)
{
return source.Update(
new ReplaceVariablesWithConstantsVisitor().Visit(source.Body),
source.Parameters);
}
class ReplaceVariablesWithConstantsVisitor : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
var expression = Visit(node.Expression);
if (expression is ConstantExpression)
{
var variable = ((ConstantExpression)expression).Value;
var value = node.Member is FieldInfo ?
((FieldInfo)node.Member).GetValue(variable) :
((PropertyInfo)node.Member).GetValue(variable);
return Expression.Constant(value, node.Type);
}
return node.Update(expression);
}
}
}
这篇关于用变量的常量动态生成lambda表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!