如何使用Lambda表达式选择多列过滤器

3

有没有一种简短的方式,不需要在每种情况下都使用"if state"? 你觉得呢? 描述:查询类型为IQueryable。

public class OrderFilter{
     public string SearchValue { get => _searchValue.ToLower(); set => _searchValue = value; }
     public string[] SearchColumns { get; set; }
}
if (!string.IsNullOrWhiteSpace(orderFilter.SearchValue))
            
   if (orderFilter.SearchColumns.Contains("warehouse"))
       query = query.Where(x => x.Warehouse.Description.Contains(orderFilter.SearchValue));
   if (orderFilter.SearchColumns.Contains("date"))
      query = query.Where(x => x.Date.Contains(orderFilter.SearchValue));
   if (orderFilter.SearchColumns.Contains("warehouse") && orderFilter.SearchColumns.Contains("date"))
      query = query.Where(x => x.OrderNo.Contains(orderFilter.SearchValue)
                    || x.Warehouse.Description.Contains(orderFilter.SearchValue)
                    || x.Client.Description.Contains(orderFilter.SearchValue)
                    || x.Date.ToString().Contains(orderFilter.SearchValue)
                    || x.Salesman.Username.Contains(orderFilter.SearchValue)
                    );
            } 

enter image description here

3个回答

1

使用Linq.Expression动态Lambda访问嵌套属性 找到了我需要的答案

public class LambdaHelper
    {
        public Expression<Func<TSource, bool>> MultiSearchOrder<TSource>(string[] columns, string value)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(TSource), "x"); // x=>  . ... demektir. parametre
            MethodInfo containsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
            Expression dynamiclambda = null;
            MethodCallExpression call = null;
            foreach (var propertyName in columns)
            {

                MemberExpression propertyAccess = NestedExpressionProperty(parameter, propertyName);
                call = Expression.Call(propertyAccess, containsMethod, Expression.Constant(value));
                if (null == dynamiclambda)
                {
                    dynamiclambda = call;
                }
                else
                {
                    dynamiclambda = Expression.Or(dynamiclambda, call);
                }
            }
            Expression<Func<TSource, bool>> predicate = Expression.Lambda<Func<TSource, bool>>(dynamiclambda, parameter);

            return predicate;

        }
 
        private MemberExpression NestedExpressionProperty(Expression expression, string propertyName)
        {
            string[] parts = propertyName.Split('.');
            int partsL = parts.Length;

            return (partsL > 1)
                ?
                Expression.Property(
                    NestedExpressionProperty(
                        expression,
                        parts.Take(partsL - 1)
                            .Aggregate((a, i) => a + "." + i)
                    ),
                    parts[partsL - 1])
                :
                Expression.Property(expression, propertyName);
        }

0

我认为你可以添加一个属性(SearchKey),该属性包含用于写入时搜索的所有属性值,并使用此属性代替OR,例如:

 savingTime: SearhKey="OrderNo.value Warehouse.Description.Value ...."

 Searching Time:
 if (!string.IsNullOrWhiteSpace(orderFilter.SearchValue))
 {
     query = query.Where(x => 
    x.SearchKey.Contains(orderFilter.SearchValue) );
 }

0

你可以创建一个 OrderFilter 的扩展并重复使用它:

public static bool HasAny<TSource>(this OrderFilter filter, IEnumerable<TSource> source)
{
    if(filter == null)
        throw new ArgumentNullException(nameof(filter));

    if(filter.SearchColumns == null)
        throw new ArgumentNullException(nameof(filter.SearchColumns));
    
    if(string.IsNullOrWhiteSpace(filter.SearchValue))
        throw new ArgumentNullException(nameof(filter.SearchValue));

    if(source == null)
        throw new ArgumentNullException(nameof(source));
    
    var properties = typeof(TSource).GetProperties().Where(x=> filter.SearchColumns.Any(s=> s.IndexOf(x.Name, StringComparison.InvariantCultureIgnoreCase) > 0));

    foreach(var item in source)
    {
        foreach(var property in properties)
        {
            var value = property.GetValue(item)?.ToString();
            
            if(value?.Equals(filter.SearchValue , StringComparison.InvariantCultureIgnoreCase) == true)
            {
                return true;
            }
        }

    }
    
    return false;
}

现在你可以这样做:

var isValueExists = orderFilter.HasAny(query);

谢谢您的回答,但我不想要这个,我已经编辑了问题。 - Cll
公共类OrderFilter{ 公共字符串SearchValue { 获取 => _searchValue.ToLower(); 设置 => _searchValue = value; } 公共字符串[] SearchColumns { 获取; 设置; } } - Cll
@Cll 谢谢,你是在寻找一种搜索单个集合中所有列的方法吗? - iSR5
动态查询选择列的示例,例如仅选择两个列orderNo和warehouse或仅选择orderNo或仅选择日期或仅选择业务员。我编辑了问题,您应该看一下。 - Cll
@Cll 谢谢,我已经更新了我的答案。不过,你可以在客户端上进行动态搜索(使用JS、纯JS或使用类库如jQuery dataTable),这样会更有效率。 - iSR5
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接