如何在运行时为LINQ和Entity Framework生成链式方法表达式?

 滨州电信1988_259 发布于 2023-02-06 11:30

我正在使用一个小型库,在运行时生成"where"表达式.我已经能够使用不同的运算符导航对象属性和查询Expression.Equal,Expression.NotEqual甚至是.Contains()字符串上的方法.

我遇到了一种情况,我需要创建一个表示链式方法的表达式,如下所示:x => x.SomeColumn.Trim().EndsWith("SomeText").我不知道从哪里开始.

.EndsWith()已经像这样实现了这个方法:

static Expression> GetEndsWithExpression(
    ParameterExpression parameterExpression,
    Expression propertyExpression,
    Expression valueToFind)
{
    var propertyExp = propertyExpression;
    var method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
    var someValue = valueToFind;
    var containsMethodExp = Expression.Call(propertyExp, method, someValue);

    return Expression.Lambda>(containsMethodExp, parameterExpression);
}

我想知道你是否可以帮我弄清楚如何添加.Trim()方法并将其与.EndsWith()方法链接起来.

其他一些信息,我已经在我的项目中使用了LINQKit,所以.AsExpandable()对我来说有些熟悉.

我的初始(错误)方法(更新)

我认为解决方案看起来像这样:

static Expression> GetTrimEndsWithExpression(
    ParameterExpression parameterExpression,
    Expression propertyExpression,
    Expression valueToFind)
{
    var propertyExp = propertyExpression;

    var trimMethod = typeof(string).GetMethod("Trim");
    var endsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });

    var trimMethodExpression = Expression.Call(propertyExp, trimMethod).Expand();
    var containsMethodExp = Expression.Call(trimMethodExpression, endsWithMethod, valueToFind);

    return Expression.Lambda>(containsMethodExp, parameterExpression);
}

但是,这无法编译.它抛出一个错误:

System.Reflection.AmbiguousMatchException: Ambiguous match found.

如何在运行时生成的表达式中链接这两个方法?

1 个回答
  • 处理这个问题的简单方法是编写一个Compose方法,允许您在另一个表达式中组合一个表达式,这在一般情况下解决了这个问题:

    public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(
        this Expression<Func<T, TIntermediate>> first,
        Expression<Func<TIntermedaite, TResult>> second)
    {
        return Expression.Lambda<Func<T, TResult>>(
            second.Body.Replace(second.Parameters[0], first.Body),
            first.Parameters[0]);
    }
    

    它使用该Replace方法将一个表达式的所有实例替换为另一个表达式,如下所示:

    public class ReplaceVisitor:ExpressionVisitor
    {
        private readonly Expression from, to;
        public ReplaceVisitor(Expression from, to)
        {
            this.from = from;
            this.to = to;
        }
    
        public override Expression Visit(Expression ex)
        {
            if(ex == from) to;
            else return base.Visit(ex);
        }  
    }
    
    public static Expression Replace(this Expression ex,
        Expression from,
        Expression to)
    {
        return new ReplaceVisitor(from, to).Visit(ex);
    }
    

    现在我们有了这个,我们可以组合我们想要的表达式:

    public static Expression<Func<TEntity, bool>> EndsWith<TEntity>(
        public Expression<Func<TEntity, string>> propertySelector,
        string endsWith)
    {
        return propertySelector.Compose(str => str.Trim().EndsWith(endsWith));
    }
    

    2023-02-06 11:33 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有