2013-07-18 3 views
3

Возможно ли построить допустимый запрос Linq, содержащий подстановочные знаки?Подстановочные знаки Entity Framework & Linq

Я видел различные ответы на этот вопрос, который предлагают использовать:

.Where(entity => entity.Name.Contains("FooBar")) 
.Where(entity => entity.Name.EndsWith("Bar")) 
.Where(entity => entity.Name.StartsWith("Foo")) 

ИЛИ Построив RawSql:

var commandText = 
    @"SELECT field 
    FROM  table 
    WHERE field LIKE @search"; 

var query = new ObjectQuery<Profile>(commandText, context); 
query.Parameters.Add(new ObjectParameter("search", wildcardSearch)); 

Первое решение не будет работать, если подстановочные не было в начале или конец строки, например, searchTerm = "Foo%Bar".

Второе решение, использующее RawSql, не сидит прямо со мной и выглядит как дешевый выход. Но это действительно работает.

Третий вариант, который мне еще предстоит испытать, - создать что-то, что может анализировать поисковый запрос и построить корректный запрос Linq, что-то, что @Slauma имеет в ссылке 2 ниже. Но это все равно не будет работать, если шаблон не был в начале или в конце поискового запроса.

Итак, вопрос: возможно ли построить допустимый запрос Linq, содержащий подстановочные знаки?

EDIT: Стоит отметить, что в этом случае я использую Oracle Data Access Components (ODAC/ODP), но я не думаю, что это имеет большое значение в этом случае.

ссылки:

1. “like” queries in Entity Framework

2. exact and wildcard searching conditional on search term

3. Using RawSql

+0

Я знаю, что это старый вопрос, но вы можете использовать идею от ответа здесь: http://stackoverflow.com/questions/1040380/wildcard-search-for-linq/42307642#42307642 Eсть а не возможность добавления подстановочных знаков в строку, но вы можете построить запрос LIKE, который вы хотите. –

ответ

0

использование SqlFunctions.PatIndex, это будет выглядеть следующим образом:

.Where(entity => SqlFunctions.PatIndex("Foo%Bar", entity.Name) > 0) 
+0

Извините, просто увидел, что вы используете Oracle, что может очень хорошо изменить ситуацию, но не уверен, что patindex будет работать для этого. – BlackICE

+0

Да, я просто обновил вопрос, чтобы показать, что я использую Oracle, будет удивлен, если нет эквивалента. Я сейчас изучаю это, спасибо. – philreed

+0

Я не могу найти версию PatIndex для Oracle, но мне стало интересно о потенциале 'string.IndexOfAny (searchTerm.Split ('%')). Необходимо немного изменить, чтобы убедиться, что сплит-термины были в правильной последовательности. – philreed

2

Если вы используете файл EDMX в качестве основы для своей модели Entity Model, возможно, вы можете попробовать создать Conceptual Model Function, который затем выполняет LIKE в SQL. Я не уверен, что это сработает для Oracle. Затем вы должны сделать что-то вроде:

.Where(entity => Like(entity.Name, "Foo%Bar")) 
+0

Я использую Code First без EDMX для существующей базы данных, но я рассмотрю ее, спасибо. – philreed

+0

Я изо всех сил пытаюсь найти способ сделать это без EDMX, но хорошая идея. – philreed

+0

@philreed Я попытался найти некоторую информацию о том, как это сделать с Code First, но также появился пустым. Одна ссылка, которую я нашел, была с 2011 года на форуме Microsoft, где она была запрошенной функцией, но, как известно, ее не поддерживали в то время. –

0

Я нашел отличное решение для Oracle. Это часть от другого ответа здесь, и часть, написанная мной.

public static class LinqExtensions 
{ 
    public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, String Name, String value) 
    { 
     Type model = typeof(T); 
     ParameterExpression param = Expression.Parameter(typeof(T), "m"); 
     PropertyInfo key = model.GetProperty(Name); 
     MemberExpression lhs = Expression.MakeMemberAccess(param, key); 
     Expression<Func<T, String>> lambda = Expression.Lambda<Func<T, String>>(lhs, param); 

     return source.Where(BuildLikeExpression(lambda, value)); 
    } 
    public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, Expression<Func<T, String>> valueSelector, String value) 
    { 
     return source.Where(BuildLikeExpression(valueSelector, value)); 
    } 
    public static Expression<Func<T, Boolean>> BuildLikeExpression<T>(Expression<Func<T, String>> valueSelector, String value) 
    { 
     if (valueSelector == null) 
      throw new ArgumentNullException("valueSelector"); 
     value = value.Replace("*", "%");  // this allows us to use '%' or '*' for our wildcard 
     if (value.Trim('%').Contains("%")) 
     { 
      Expression myBody = null; 
      ParsedLike myParse = Parse(value); 
      Type stringType = typeof(String); 
      if(myParse.startwith!= null) 
      { 
       myBody = Expression.Call(valueSelector.Body, stringType.GetMethod("StartsWith", new Type[] { stringType }), Expression.Constant(myParse.startwith)); 
      } 
      foreach (String contains in myParse.contains) 
      { 
       if (myBody == null) 
       { 
        myBody = Expression.Call(valueSelector.Body, stringType.GetMethod("Contains", new Type[] { stringType }), Expression.Constant(contains)); 
       } 
       else 
       { 
        Expression myInner = Expression.Call(valueSelector.Body, stringType.GetMethod("Contains", new Type[] { stringType }), Expression.Constant(contains)); 
        myBody = Expression.And(myBody, myInner); 
       } 
      } 
      if (myParse.endwith != null) 
      { 
       if (myBody == null) 
       { 
        myBody = Expression.Call(valueSelector.Body, stringType.GetMethod("EndsWith", new Type[] { stringType }), Expression.Constant(myParse.endwith)); 
       } 
       else 
       { 
        Expression myInner = Expression.Call(valueSelector.Body, stringType.GetMethod("EndsWith", new Type[] { stringType }), Expression.Constant(myParse.endwith)); 
        myBody = Expression.And(myBody, myInner); 
       } 
      } 
      return Expression.Lambda<Func<T, Boolean>>(myBody, valueSelector.Parameters.Single()); 
     } 
     else 
     { 
      Expression myBody = Expression.Call(valueSelector.Body, GetLikeMethod(value), Expression.Constant(value.Trim('%'))); 
      return Expression.Lambda<Func<T, Boolean>>(myBody, valueSelector.Parameters.Single()); 
     } 
    } 
    private static MethodInfo GetLikeMethod(String value) 
    { 
     Type stringType = typeof(String); 

     if (value.EndsWith("%") && value.StartsWith("%")) 
     { 
      return stringType.GetMethod("Contains", new Type[] { stringType }); 
     } 
     else if (value.EndsWith("%")) 
     { 
      return stringType.GetMethod("StartsWith", new Type[] { stringType }); 
     } 
     else 
     { 
      return stringType.GetMethod("EndsWith", new Type[] { stringType }); 
     } 
    } 
    private class ParsedLike 
    { 
     public String startwith { get; set; } 
     public String endwith { get; set; } 
     public String[] contains { get; set; } 
    } 
    private static ParsedLike Parse(String inValue) 
    { 
     ParsedLike myParse = new ParsedLike(); 
     String work = inValue; 
     Int32 loc; 
     if (!work.StartsWith("%")) 
     { 
      work = work.TrimStart('%'); 
      loc = work.IndexOf("%"); 
      myParse.startwith = work.Substring(0, loc); 
      work = work.Substring(loc + 1); 
     } 
     if (!work.EndsWith("%")) 
     { 
      loc = work.LastIndexOf('%'); 
      myParse.endwith = work.Substring(loc + 1); 
      if (loc == -1) 
       work = String.Empty; 
      else 
       work = work.Substring(0, loc); 
     } 
     myParse.contains = work.Split(new[] { '%' }, StringSplitOptions.RemoveEmptyEntries); 
     return myParse; 
    } 
} 
Смежные вопросы