实体框架中的“喜欢”查询

时间:2010-03-30 01:25:23

标签: entity-framework wildcard

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

我认为这样可行:

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

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

6 个答案:

答案 0 :(得分:7)

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

  • x% - > startswith
  • %x - >的endsWith
  • %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 });
        }
    }
}

答案 1 :(得分:5)

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:3)

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

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

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

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

答案 4 :(得分:2)

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

然而,我发现它并没有真正起作用,特别是在使用LOAD时。也就是说,它使用IEnumerable并使用正则表达式来匹配可枚举,而不是内置函数。

由于我只想在完成过滤后解析ToArray,我做了一些更改以转换为IEnumerable,然后使用其余代码来查找正确的Entity Framework方法并调用那。这样,直到稍后才会对数据库调用查询本身,并且它避免使用正则表达式。

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

答案 5 :(得分:0)

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