【问题标题】:"like" queries in Entity Framework实体框架中的“喜欢”查询
【发布时间】:2010-03-30 01:25:22
【问题描述】:

如何使用 edo 实体框架在 ASP.net MVC 中进行通配符文本搜索(如 SQL 的“like”语句)?

我认为这会起作用:

var elig = (from e in _documentDataModel.Protocol_Eligibility_View
            where e.criteria.Contains(query)
            select e);

但即使搜索肯定在数据库中的查询字符串,它也不会返回任何结果。我做错了什么?

【问题讨论】:

    标签: entity-framework wildcard


    【解决方案1】:

    这家伙为 Linq 做了一个非常好的“WhereLike”扩展,它接受任何通配符并将两个值(其中一个来自表达式)与从通配符位置派生的通用方法进行比较。

    • x% -> 开始于
    • %x -> 以
    • 结尾
    • %x% -> 包含

    http://trentacular.com/2010/08/linq-to-entities-wild-card-like-extension-method/

    编辑: 文章好像下架了。我将在下面粘贴扩展代码:

    public static class LinqHelper
        {
            //Support IQueryable (Linq to Entities)
            public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> valueSelector, string value, char wildcard)
            {
                return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
            }
    
            //Support IEnumerable (Linq to objects)
            public static IEnumerable<TSource> WhereLike<TSource>(this IEnumerable<TSource> sequence, Func<TSource, string> expression, string value, char wildcard)
            {
                var regEx = WildcardToRegex(value, wildcard);
    
                //Prevent multiple enumeration:
                var arraySequence = sequence as TSource[] ?? sequence.ToArray();
    
                try
                {
                    return arraySequence.Where(item => Regex.IsMatch(expression(item), regEx));
                }
                catch (ArgumentNullException)
                {
                    return arraySequence;
                }
            }
    
            //Used for the IEnumerable support
            private static string WildcardToRegex(string value, char wildcard)
            {
                return "(?i:^" + Regex.Escape(value).Replace("\\" + wildcard, "." + wildcard) + "$)";
            }
    
            //Used for the IQueryable support
            private static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(Expression<Func<TElement, string>> valueSelector, string value, char wildcard)
            {
                if (valueSelector == null) throw new ArgumentNullException("valueSelector");
    
                var method = GetLikeMethod(value, wildcard);
    
                value = value.Trim(wildcard);
                var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value));
    
                var parameter = valueSelector.Parameters.Single();
                return Expression.Lambda<Func<TElement, bool>>(body, parameter);
            }
    
            private static MethodInfo GetLikeMethod(string value, char wildcard)
            {
                var methodName = "Equals";
    
                var textLength = value.Length;
                value = value.TrimEnd(wildcard);
                if (textLength > value.Length)
                {
                    methodName = "StartsWith";
                    textLength = value.Length;
                }
    
                value = value.TrimStart(wildcard);
                if (textLength > value.Length)
                {
                    methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith";
                }
    
                var stringType = typeof(string);
                return stringType.GetMethod(methodName, new[] { stringType });
            }
        }
    }
    

    【讨论】:

    • 不幸的是,答案中提供的此链接已失效。感谢您提供代码。
    • 如何使用扩展方法?
    • 在任何 IQueryable 或 IEnumerable 上调用它,如下所示: IQueryableVar.WhereLike(item => item.property, textbox.Text, '*');其中 textbox.Text 是您希望属性是什么样的示例。
    • 谢谢乔恩,第三个参数'*'是做什么的?
    • 如您所见,它一直传递到方法“GetLikeMethod”,用于确定是使用 StartsWith、EndsWith 还是 Contains。因此,如果您的值是“bla*”,这可能意味着您需要以“bla”开头的所有内容,则将 * 字符与通配符参数一起传递,并期望该方法返回“Startswith("bla")”。跨度>
    【解决方案2】:

    2019 年更新

    对于 Entity Framework 6.2,您可以使用 DBFunctions

    例如:

    try
    {
        using (var db = new YOUREntities())
        {
            var data = db.LenderProgram.Where(i => DbFunctions.Like(i.LenderProgramCode, "OTO%"))
                .ToList();
            return data;
        }
    }
    catch (Exception e)
    {
        e.HandleException();
    }
    

    【讨论】:

      【解决方案3】:

      String.Contains 应该可以正常工作。 SQL 的 LIKE 语句通常通过 String.StartsWith、String.Contains 或 String.EndsWith 处理。

      但是,您可能遇到了大小写问题。你可以试试:

      var elig = (from e in _documentDataModel.Protocol_Eligibility_View
              where e.criteria.ToLower().Contains(query.ToLower())
              select e);
      

      【讨论】:

      • 仔细查看我的问题后,我的问题似乎在其他地方,而不是在 .contains 语句中。
      【解决方案4】:

      Linq to entity 不支持 SqlMethods 方法,但您可以改用字符串函数:

      .Where(entity => entity.Name.Contains("xyz"))
      
      .Where(entity => entity.Name.EndsWith("xyz"))
      
      .Where(entity => entity.Name.StartsWith("xyz"))
      

      【讨论】:

        【解决方案5】:

        System.Data.Linq.SqlClient 命名空间包含 SqlMethods 类。你可以像这样使用它的 Like 方法:

        var elig = from e in _documentDataModel.Protocol_Eligibility_View
                   where SqlMethods.Like(e.criteria, query)
                   select e;
        

        【讨论】:

          【解决方案6】:

          我开始使用 Jon Koeter 从博客文章中发布的代码在另一个似乎不再存在的答案中。

          但是,我发现它并不能正常工作,尤其是在使用IEnumerable 时。也就是说,它使用ToArray 解析可枚举并使用正则表达式进行匹配,而不是内置函数。

          由于我只想在完成过滤后解析我的IEnumerable,因此我进行了一些更改以转换为IQueryable,然后使用其余代码找到正确的实体框架方法并调用它。这样,查询本身直到稍后才会针对数据库调用,并且避免了使用正则表达式。

          public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, Expression<Func<T, string>> valueSelector, string value, char wildcard)
          {
              return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
          }
          
          public static IEnumerable<T> WhereLike<T>(this IEnumerable<T> source, Expression<Func<T, string>> valueSelector, string value, char wildcard)
          {
              return source.AsQueryable().WhereLike(valueSelector, value, wildcard);
          }
          
          private static Expression<Func<T, bool>> BuildLikeExpression<T>(Expression<Func<T, string>> valueSelector, string value, char wildcard)
          {
              if (valueSelector == null) throw new ArgumentNullException("valueSelector");
          
              var method = GetLikeMethod(value, wildcard);
              value = value.Trim(wildcard);
              var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value));
              var parameter = valueSelector.Parameters.Single();
              return Expression.Lambda<Func<T, bool>>(body, parameter);
          }
          
          private static MethodInfo GetLikeMethod(string value, char wildcard)
          {
              var methodName = "Equals";
          
              var textLength = value.Length;
              value = value.TrimEnd(wildcard);
              if (textLength > value.Length)
              {
                  methodName = "StartsWith";
                  textLength = value.Length;
              }
          
              value = value.TrimStart(wildcard);
              if (textLength > value.Length)
              {
                  methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith";
              }
          
              var stringType = typeof(string);
              return stringType.GetMethod(methodName, new[] { stringType });
          }
          

          用法:

          // example data set
          var data = new List<Person> {
              new Person{FirstName="John", LastName="Smith"}, 
              new Person{FirstName="Jane", LastName="Doe"}
          };
          
          data.WhereLike(x=>x.FirstName, "John", "%"); // returns John Smith
          data.WhereLike(x=>x.FirstName, "J%", "%"); // returns John Smith and Jane Smith
          

          【讨论】:

          • 我不得不说,这篇文章只有 IQueryable 的代码,我认为它可以创造奇迹。我自己添加了 IEnumerable 代码(可能是从另一个网站获取的,不记得了),我想我不妨与你们分享。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-20
          • 1970-01-01
          • 2014-03-30
          • 1970-01-01
          • 2012-12-23
          • 2012-09-18
          相关资源
          最近更新 更多