entity framework通配符和Linq

是否可以构造包含通配符的有效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(commandText, context); query.Parameters.Add(new ObjectParameter("search", wildcardSearch)); 

如果通配符不在字符串的开头或结尾,则第一个解决方案将不起作用,例如, searchTerm = "Foo%Bar"

第二个解决方案,使用RawSql,并不适合我,感觉就像一个廉价的出路。 但它确实有效。

我还没有尝试的第三个选项是创建一些可以解析搜索词并构造有效的Linq查询的东西,这是@Slauma在下面的链接2中进行的操作。 但是,如果通配符不在搜索词的开头或结尾,这仍然不起作用。

所以问题是:是否可以构造一个包含通配符的有效Linq查询?

编辑:值得一提的是,在这个实例中我使用的是Oracle数据访问组件(ODAC / ODP),但我认为在这种情况下它没有太大区别。

链接:

1. entity framework中的“喜欢”查询

2. 以搜索词为条件的精确和通配符搜索

3. 使用RawSql

如果您使用EDMX文件作为实体模型的基础,那么也许您可以尝试创建一个概念模型函数 ,然后在SQL中执行LIKE。 我不确定这是否适用于Oracle。 然后,您应该能够执行以下操作:

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

使用SqlFunctions.PatIndex,它看起来像这样:

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

我找到了一个很棒的Oracle解决方案。 这是另一个答案的一部分,也是我写的部分。

  public static class LinqExtensions { public static IQueryable WhereLike(this IQueryable 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> lambda = Expression.Lambda>(lhs, param); return source.Where(BuildLikeExpression(lambda, value)); } public static IQueryable WhereLike(this IQueryable source, Expression> valueSelector, String value) { return source.Where(BuildLikeExpression(valueSelector, value)); } public static Expression> BuildLikeExpression(Expression> 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>(myBody, valueSelector.Parameters.Single()); } else { Expression myBody = Expression.Call(valueSelector.Body, GetLikeMethod(value), Expression.Constant(value.Trim('%'))); return Expression.Lambda>(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; } }