【问题标题】:Expression.Like in C#Expression.Like 在 C# 中
【发布时间】:2014-06-25 09:31:49
【问题描述】:

例如:x=> x.Name = "g"

我有这样的代码块

public Expression<Func<TEntity, bool>> SearchExpression()
{
    var c = new ConstantExpression[_paramList.Count];
    var b = new BinaryExpression[_paramList.Count];
    BinaryExpression comparisonExpression = null;

    var entity = Expression.Parameter(typeof(TEntity));

    for (int i = 0; i < _paramList.Count; i++)
    {
        var value = Convert.ChangeType(_paramList[i].Item2 /*"g"*/, _paramList[i].Item3 /*System.String*/);
        c[i] = Expression.Constant(value); //"g"

        // PROBLEM IS HERE
        b[i] = Expression.Equal(Expression.Property(entity, _paramList[i].Item1 /*Name*/, c[i]);
        // PROBLEM IS HERE



    }
    _paramList.Clear();
    comparisonExpression = b.Aggregate(Expression.And);
    return Expression.Lambda<Func<TEntity, bool>>(comparisonExpression, entity);
}

像魅力一样工作,但我需要 Expression.Like (像“g”不等于“g”)

Expression.Like(Expression.Property(entity, _paramList[i].Item1), c[i])

但是C#表达式树不支持Like方法

更新

我写了这样的东西:

Expression.Call(Expression.Property(entity, _paramList[i].Item1),
                typeof(String).GetMethod("Contains"), new Expression[] { c[i] });  

但我需要 BinaryExpression 而不是 MethodCallExpression

【问题讨论】:

  • 我认为您需要向 string.Contains 注入方法调用。 Expression.Like 不是开箱即用的表达式。
  • @Adrian Wragg,在 ExpressionTree 中不是字符串!!!!!!!!!!!!!!!
  • @user3432343 可能。如果你说不是,我会撤回接近投票。
  • Marc Gravell 做了类似的事情 here
  • @chridam,是的,我看到了,但我不能在我的代码块中使用它:(

标签: c# expression-trees sql-like


【解决方案1】:

您可以通过在方法调用上添加一个等于表达式来使您的代码正常工作,如下所示:

    b[i] = Expression.Equal(
        Expression.Call(Expression.Property(entity, _paramList[i].Item1),
        typeof (String).GetMethod("Contains"), 
          new Expression[] {c[i]}), Expression.Constant(true));

伪代码如下:

b[i] = entity => entity.someProperty.Contains(c[i]) == true;

这将为您返回一个二进制表达式。

【讨论】:

    【解决方案2】:

    此答案不考虑您的数组和“和”聚合,但这应该被视为一个单独的问题。

    考虑这个类:

    class MyEntity { string Name { get; set; } }
    

    我们要查询:

    select ... from MyEntity where Name like '%query%';
    

    以下方法是上述查询模式的一般实现:

    static Expression<Func<TEntity, bool>> Like<TEntity>(string propertyName, string queryText)
    {
        var parameter = Expression.Parameter(typeof (TEntity), "entity");
        var getter = Expression.Property(parameter, propertyName);
        //ToString is not supported in Linq-To-Entities, throw an exception if the property is not a string.
        if (getter.Type != typeof (string))
            throw new ArgumentException("Property must be a string");
        //string.Contains with string parameter.
        var stringContainsMethod = typeof (string).GetMethod("Contains", new[] {typeof (string)});
        var containsCall = Expression.Call(getter, stringContainsMethod,
            Expression.Constant(queryText, typeof (string)));
    
        return Expression.Lambda<Func<TEntity, bool>>(containsCall, parameter);
    }
    

    如果您想要query%%query 的模式,您可以使用string.StartsWithstring.EndsWith 而不是Contains

    此外,如果您调整签名,您可以在多个调用之间共享参数。

    如果属性的数据类型不是字符串,当前实现会抛出异常。看看这个答案https://stackoverflow.com/a/3292773/668272 将数字转换为字符串。

    【讨论】:

    • 从 EF 6.1 开始,最后一条语句不再正确。我为它写了 contrib :).. 所以你可以连接字符串和原语,也可以在非字符串中调用 .ToString() ..
    【解决方案3】:

    我已经用我编写的脚本语言完成了这项工作,它允许您说出name like 'bob%' 之类的内容。诀窍是您需要将其映射到一个方法调用,该方法调用采用值和正则表达式并从Expression 中调用它。

    如果您看一下我的 Wire 脚本语言中的 LikeEvaluator 类,您就会知道我是如何做到的:

    static class LikeEvaluator
    {
        private static readonly MethodInfo ApplyLikeMethodInfo=typeof(LikeEvaluator).GetMethod("ApplyLike");
        private static readonly MethodInfo ApplyLikeNoCaseMethodInfo=typeof(LikeEvaluator).GetMethod("ApplyLikeNoCase");
    
        public static Expression Like(CaseMode caseMode, Expression lhs, Expression pattern)
        {
            Expression x=null;
    
            if(caseMode==CaseMode.Sensitive)
            {
                x=Expression.Call(ApplyLikeMethodInfo,lhs,pattern);
            }
            else
            {
                x=Expression.Call(ApplyLikeNoCaseMethodInfo,lhs,pattern);
            }
    
            return x;
        }
    
        public static bool ApplyLike(string text, string likePattern)
        {
            string pattern=PatternToRegex(likePattern);
            return Regex.IsMatch(text,pattern,RegexOptions.None);
        }
    
        public static bool ApplyLikeNoCase(string text, string likePattern)
        {
            string pattern=PatternToRegex(likePattern);
            return Regex.IsMatch(text,pattern,RegexOptions.IgnoreCase);
        }
    
        public static string PatternToRegex(string pattern)
        {
            pattern=Regex.Escape(pattern);
            pattern=pattern.Replace("%",@".*");
            pattern=string.Format("^{0}$",pattern);
    
            return pattern;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-13
      • 1970-01-01
      • 2016-03-30
      • 1970-01-01
      • 2013-01-18
      • 2013-09-20
      • 1970-01-01
      • 1970-01-01
      • 2010-11-19
      相关资源
      最近更新 更多