转换LINQ扩展方法以使用L2E

时间:2013-04-08 21:54:38

标签: c# linq entity-framework linq-to-entities

我正在使用搜索页面,用户可以在搜索条件中使用通配符*。通配符可以放在字符串的开头或结尾处。由于我需要将几个字段应用于此,我认为扩展方法是最好的方法。我提出的代码目前有效,但不适用于IQueryable

public static class Helper
{
    public static IEnumerable<string> MyExtMethod(this IEnumerable<string> items, string searchString)
    {
        var searchType = -1;    
        if(searchString.IndexOf("*") == -1) //No wildcard
        {
            searchType = 0;
        }
        else if(searchString.IndexOf("*") == 0 && searchString.LastIndexOf("*") == searchString.Length - 1)//start and end
        {
            searchType = 1;
        }
        else if(searchString.IndexOf("*") == 0)//ends with
        {
            searchType = 2;
        }
        else if(searchString.LastIndexOf("*") == searchString.Length - 1) //starts with
        {
            searchType = 3;
        }

        var search = searchString.Replace("*", "");

        foreach(var i in items)
        {
            switch(searchType)
            {
                case 0: yield return i;
                break;
                case 1: if(i.Contains(search))
                            yield return i;
                break;
                case 2: if(i.EndsWith(search))
                            yield return i;
                break;
                case 3: if(i.StartsWith(search))
                            yield return i;
                break;
            }
        }
    }
}

我只使用L2E ContainsStartsWithEndsWith已经支持的字符串操作和扩展方法。这可以转换为与实体一起使用吗?如果是这样,需要做什么?感谢。

编辑: 如果可能的话,我希望能够这样使用它:

db.SomeTable.Where(s => s.SomeField.MyExtMethod(somestring));

参考来源的奖励积分。

2 个答案:

答案 0 :(得分:3)

EF使用IQueryable<T> - 而不是IEnumerable<T>

所以这样的事情应该做:

public static class Helper
{
  public static IQueryable<Table> SearchText(
    this IQueryable<Table> q,
    string searchString
  )
  {
    var searchType = -1;    
    if(searchString.IndexOf("*") == -1)
    {
        searchType = 0; // No wildcard
    }
    else if(searchString.IndexOf("*") == 0 &&
      searchString.LastIndexOf("*") == searchString.Length - 1)
    {
        searchType = 1; // start and end
    }
    else if(searchString.IndexOf("*") == 0)
    {
        searchType = 2; // ends with
    }
    else if(searchString.LastIndexOf("*") == searchString.Length - 1)
    {
        searchType = 3; // starts with
    }

    var search = searchString.Replace("*", "");

    switch(searchType)
    {
      default:
      case 0: return q.Where( o => o == search );
      case 1: return q.Where( o => o.Text.Contains( search ) );
      case 2: return q.Where( o => o.Text.EndsWith( search ) );
      case 3: return q.Where( o => o.Text.StartsWith( search ) );
    }
  }
}

Table.Text是您要搜索的属性。

然后你可以像这样使用它:

IQueryable<Table> q = dbContext.Table;

var matches = q.SearchText( searchString ).ToList();

答案 1 :(得分:0)

我在internet周围找到了一些基本代码,并稍微修改了它,以便我可以使用它。

  • abc:匹配“abc”完全
  • * abc:如果字符串以“abc”
  • 结尾,则匹配
  • abc *:如果字符串以“abc”
  • 开头,则匹配
  • * abc *:匹配,如果字符串包含“abc”
public static class LinqExtensions
{
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));
}

        public 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";
                textLength = value.Length;
            }

            var stringType = typeof(string);
            return stringType.GetMethod(methodName, new Type[] { stringType });
        }
    }