«похожие» запросы в Entity Framework - PullRequest
3 голосов
/ 30 марта 2010

Как получить текстовый поиск с подстановочными знаками (например, SQL-выражение "like") в ASP.net MVC с использованием инфраструктуры сущностей edo?

Я предполагал, что это сработает:

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

Но он не возвращает результатов даже при поиске строки запроса, которая определенно находится в базе данных. Что я делаю не так?

Ответы [ 5 ]

7 голосов
/ 27 марта 2015

Этот парень сделал очень хорошее расширение "WhereLike" для Linq, которое принимает любой символ подстановки и сравнивает два значения (одно из которых происходит из выражения) с универсальным методом, полученным из местоположения символа подстановки.

  • x% -> начинается с
  • % x -> заканчивается
  • % x% -> содержит

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

EDIT: Статья кажется внизу. Я вставлю код расширения ниже:

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 });
        }
    }
}
5 голосов
/ 30 марта 2010

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);
4 голосов
/ 26 июля 2012

Linq для сущностей не поддерживает метод SqlMethods, но вместо этого вы можете использовать строковые функции:

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

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

.Where(entity => entity.Name.StartsWith("xyz"))
3 голосов
/ 25 июля 2011

Пространство имен System.Data.Linq.SqlClient содержит класс SqlMethods. Вы можете использовать метод Like следующим образом:

var elig = from e in _documentDataModel.Protocol_Eligibility_View
           where SqlMethods.Like(e.criteria, query)
           select e;
2 голосов
/ 06 марта 2017

Я начал использовать код, который Джон Кётер опубликовал в своем блоге в другом ответе, которого больше не существует.

Однако я обнаружил, что он не работает должным образом, особенно при использовании IEnumerable. А именно, он разрешал перечисляемое с использованием ToArray и использовал регулярное выражение для сопоставления, а не встроенные функции.

Поскольку я хочу разрешить свой IEnumerable только после завершения фильтрации, я внес некоторые изменения, чтобы преобразовать в IQueryable, а затем использовать оставшуюся часть кода, чтобы найти правильный метод Entity Framework и вызвать его. Таким образом, сам запрос не вызывается для базы данных до тех пор, пока позже, и он избегает использования регулярных выражений.

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
...