c# - 使用变量中的常量动态生成 lambda 表达式

标签 c# .net oracle entity-framework

我一直在解决一些 EF 6 代码的异常问题,即使用 Oracle.ManagedDataAccess.Client 驱动程序运行的查询有时需要几分钟才能返回结果,即使底层查询在 2 毫秒内执行也是如此。示例查询如下:

var result = users.Where(u => u.username == varUserName).FirstOrDefault();

这个查询可能需要几分钟才能返回,但是如果我用 lambda 函数中的常量替换查询,它会立即运行:

var result = users.Where(u => u.username == "testUsername").FirstOrDefault();

要解决这个问题,我可以编写参数化 SQL 查询,也可以手动生成适当的 lambda 表达式树:

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 表达式树,从而导致变量直接作为常量包含,而不是对变量的引用?

例如,像这样的东西将是理想的:

var lambdaExpression = (u => u.username == varUserName).ReplaceVariablesWithConstants();

最佳答案

使用 ExpressionVisitor 可以相对容易地完成,它像这样评估 ConstantExpression 成员:

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);
        }
    }
}

关于c# - 使用变量中的常量动态生成 lambda 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38759722/

相关文章:

c# - DevExpress MVC LabelFor - 设置 css 类

c# - Windows 窗体程序中的多个 UI

c# - 处理异常

database - Oracle中通过脚本创建新表时将列名更改为大写如何解决?

c# - 在 .NET 中,如何执行此 Oracle PL/SQL 程序?

oracle - ORA-00932 不一致的数据类型 : expected - got BLOB

c# - 为什么这个对 C# 方法的 jquery ajax GET 调用不起作用?

c# - 如何通过 IEnumerable 使用 TableQuery 进行查询?

c# - .Net 4.0 中的 ISO_IR 58 支持

c# - 子表单运行时防止初始表单出现 "refreshing"