c# – 每个提供的属性带有’OR’子句的通用表达式树
发布时间:2020-12-15 05:37:22 所属栏目:百科 来源:网络整理
导读:我为IQueryable创建了一个通用搜索扩展方法,使您可以搜索单个属性以查看其中是否包含搜索词. http://jnye.co/Posts/6/c%23-generic-search-extension-method-for-iqueryable 我现在想让用户选择多个属性来搜索每个属性,匹配是否有任何属性包含文本. 代码:
我为IQueryable创建了一个通用搜索扩展方法,使您可以搜索单个属性以查看其中是否包含搜索词.
http://jnye.co/Posts/6/c%23-generic-search-extension-method-for-iqueryable 我现在想让用户选择多个属性来搜索每个属性,匹配是否有任何属性包含文本. 代码: 用户输入以下代码以执行此搜索: string searchTerm = "Essex"; context.Clubs.Search(searchTerm,club => club.Name,club => club.County) //Note: If possible I would rather something closer to the following syntax... context.Clubs.Search(club => new[]{ club.Name,club.County},searchTerm); // ... or,even better,something similar to this... context.Clubs.Search(club => new { club.Name,searchTerm); 这将返回任何名为“Essex”的高尔夫俱乐部或郡. public static IQueryable<TSource> Search<TSource>(this IQueryable<TSource> source,string searchTerm,params Expression<Func<TSource,string>>[] stringProperties) { if (String.IsNullOrEmpty(searchTerm)) { return source; } // The lamda I would like to reproduce: // source.Where(x => x.[property1].Contains(searchTerm) // || x.[property2].Contains(searchTerm) // || x.[property3].Contains(searchTerm)...) //Create expression to represent x.[property1].Contains(searchTerm) var searchTermExpression = Expression.Constant(searchTerm); //Build parameters var parameters = stringProperties.SelectMany(prop => prop.Parameters); Expression orExpression = null; //Build a contains expression for each property foreach (var stringProperty in stringProperties) { var checkContainsExpression = Expression.Call(stringProperty.Body,typeof(string).GetMethod("Contains"),searchTermExpression); if (orExpression == null) { orExpression = checkContainsExpression; } //Build or expression for each property orExpression = Expression.OrElse(orExpression,checkContainsExpression); } var methodCallExpression = Expression.Call(typeof(Queryable),"Where",new Type[] { source.ElementType },source.Expression,Expression.Lambda<Func<TSource,bool>>(orExpression,parameters)); return source.Provider.CreateQuery<TSource>(methodCallExpression); } 错误 如果我将提供的参数数量更改为1: Expression.Lambda<Func<TSource,parameters.First())); 我收到一个新错误: UPDATE 我也写了a post on the work discussed in this question. Check it out on GitHub. 解决方法
开始了;你非常接近 – 正如我在评论中所指出的,这里的关键部分是使用ExpressionVisitor根据你想要保留的单个参数重新编写树:
using System; using System.Linq; using System.Linq.Expressions; static class Program { static void Main() { var data = new[] { new Foo { A = "x1",B = "y1",C = "y1" },new Foo { A = "y2",B = "y2",C = "y2" },new Foo { A = "y3",B = "y3",C = "x3" } }.AsQueryable(); var result = data.Search("x",x => x.A,x => x.B,x => x.C); foreach (var row in result) { Console.WriteLine("{0},{1},{2}",row.A,row.B,row.C); } } class Foo { public string A { get; set; } public string B { get; set; } public string C { get; set; } } public class SwapVisitor : ExpressionVisitor { private readonly Expression from,to; public SwapVisitor(Expression from,Expression to) { this.from = from; this.to = to; } public override Expression Visit(Expression node) { return node == from ? to : base.Visit(node); } public static Expression Swap(Expression body,Expression from,Expression to) { return new SwapVisitor(from,to).Visit(body); } } public static IQueryable<TSource> Search<TSource>(this IQueryable<TSource> source,string>>[] stringProperties) { if (String.IsNullOrEmpty(searchTerm)) { return source; } if (stringProperties.Length == 0) return source.Where(x => false); // The lamda I would like to reproduce: // source.Where(x => x.[property1].Contains(searchTerm) // || x.[property2].Contains(searchTerm) // || x.[property3].Contains(searchTerm)...) //Create expression to represent x.[property1].Contains(searchTerm) var searchTermExpression = Expression.Constant(searchTerm); var param = stringProperties[0].Parameters.Single(); Expression orExpression = null; //Build a contains expression for each property foreach (var stringProperty in stringProperties) { // re-write the property using the param we want to keep var body = SwapVisitor.Swap(stringProperty.Body,stringProperty.Parameters.Single(),param); var checkContainsExpression = Expression.Call( body,searchTermExpression); if (orExpression == null) { orExpression = checkContainsExpression; } else { // compose orExpression = Expression.OrElse(orExpression,checkContainsExpression); } } var lambda = Expression.Lambda<Func<TSource,param); return source.Where(lambda); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |