zoukankan      html  css  js  c++  java
  • Linq动态查询与模糊查询

     

    最近有个项目用Linq做的,有个复合搜索模糊查询的功能,有点麻烦,绕了好几个弯,最后是解决了,在这里分享一下我的处理过程,如果大家有更好的办法也请给我介绍一下。我用Linq还熟,好多东西边查资料边做的。 

    应用场景如下图,多条件复合搜索,很常见吧(但Linq搞这个还真是麻烦):

    阶段一:

    首先是找到了李永京(YJingLee)前辈的《LINQ体验(17)——LINQ to SQL语句之动态查询》一文,利用Lambda表达式树可以进行动态查询。

    写了个方法进行复合查询,动态组合条件,生成Lambda表达式。


     1     /// <summary>
     2     /// 这个方法带分页功能,通过输入的键值对NVC进行复合查询
     3     /// </summary>
     4     List<UserT_TractInfo> GetPagedObjectsByNVC(int startIndex, int pageSize, NameValueCollection nvc, bool isAnd)
     5     {
     6         IQueryable<UserT_TractInfo> query = Consulting.Instance.UserT_TractInfo;
     7         query.Where(t => t.IsDel == 0).Where(t => t.IsAuditing == 1);//审核和逻辑删除
     8 
     9         Expression condition = null;
    10         ParameterExpression param = Expression.Parameter(typeof(UserT_TractInfo), "c");
    11         int propertyCount = 0;
    12         foreach (string key in nvc)
    13         {
    14             Expression right = Expression.Constant(nvc[key]);//键
    15             string keyProperty = key;//属性
    16             if (typeof(UserT_TractInfo).GetProperty(keyProperty) != null)//当对象存在此属性时(因为键值对可能还有很多其他的参数,例如page)
    17             {
    18                 Expression left = Expression.Property(param, typeof(UserT_TractInfo).GetProperty(keyProperty));//建立属性
    19                 Expression filter = Expression.Equal(left, right);//过滤器
    20                 if (condition == null)
    21                 {
    22                     condition = filter;
    23                 }
    24                 else
    25                 {
    26                     if (isAnd)
    27                     {
    28                         condition = Expression.And(condition, filter);
    29                     }
    30                     else
    31                     {
    32                         condition = Expression.Or(condition, filter);
    33                     }
    34                 }
    35                 propertyCount++;
    36             }
    37         }
    38         //以上foreach组合了各个有效的键值对对应的conditionExpression,复合查询最重要的组合工作就这么完了
    39         if (propertyCount > 0)
    40         {
    41             Expression pred = Expression.Lambda(condition, param);
    42             MethodCallExpression whereCallExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(UserT_TractInfo) }, Expression.Constant(query), pred);
    43 
    44             return Consulting.Instance.UserT_TractInfo.AsQueryable().Provider.CreateQuery<UserT_TractInfo>(whereCallExpression).OrderByDescending(t => t.ID).Skip(startIndex - 1).Take(pageSize).ToList();//查询出结果
    45         }
    46         else
    47         {
    48             return Consulting.Instance.UserT_TractInfo.OrderByDescending(t => t.ID).Skip(startIndex - 1).Take(pageSize).ToList();//如果没有有效键值对,则返回全部结果
    49         }
    50     }
    51 

    搞了半天本来很兴奋的,之后才知道Lambda表达式是写不出.Contains()的,我的心瓦凉瓦凉的。

    阶段二:

    虽然李永京的文章没给我多少帮助,但它后面有个回复很有价值:“用微软提供的System.Linq.Dynamic方便点。”

    很快找到了对应例子和Dynamic.cs,也找到了《Linq to SQL Dynamic 动态查询》,有更细致的例子,可惜Dynamic.cs也是不能使用like的,恨啊!


    return Consulting.Instance.UserT_TractInfo.Where("b_number == @0","P(2007)031").OrderByDescending(t => t.ID).Skip(startIndex - 1).Take(pageSize).ToList();

    代码很容易,但没什么用:(

    阶段三:

    中文的实在是找不到了,在MS的官方BBS上找到了个链接,非常有用!《dynamic linq queries / dynamic where clause (part 2) 》,这个老外扩展了Dynamic.cs,写了个PredicateExtensions类,虽然不知道他是怎么想出来的,但确实有效!

    这里放出核心代码,很容易看懂,简单就是美! 


     1         searchPredicate = PredicateExtensions.True<UserT_TractInfo>();
     2         foreach (string key in nvcParam)
     3         {
     4             string condition = string.Empty;
     5             switch (key)
     6             {
     7                 case "b_number":
     8                     condition = nvcParam[key];
     9                     searchPredicate = searchPredicate.And(u => u.B_number.Contains(condition));
    10                     break;
    11                 case "b_address":
    12                     condition = nvcParam[key];
    13                     searchPredicate = searchPredicate.And(u => u.B_address.Contains(condition));
    14                     break;
    15                 case "b_canton":
    16                     condition = nvcParam[key];
    17                     searchPredicate = searchPredicate.And(u => u.B_canton.Contains(condition));
    18                     break;
    19                 case "a_status":
    20                     condition = nvcParam[key];
    21                     searchPredicate = searchPredicate.And(u => u.A_status.ToString().Contains(condition));
    22                     break;
    23                 case "b_area":
    24                     condition = nvcParam[key];
    25                     searchPredicate = searchPredicate.And(u => u.B_area.Contains(condition));
    26                     break;
    27                 case "c_clinchdate":
    28                     condition = nvcParam[key];
    29                     searchPredicate = searchPredicate.And(u => u.C_clinchdate.Contains(condition));
    30                     break;
    31                 default:
    32                     break;
    33             }
    34         }
    35 
    36 return Consulting.Instance.UserT_TractInfo.Where(searchPredicate).OrderByDescending(t => t.ID).Skip(startIndex - 1).Take(pageSize).ToList();

    下面是我写了注释后的PredicateExtensions,我说不清楚构造函数的True和False具体是怎么起作用的,但结果就是我的注释那样,在复合查询写条件时很重要(不过目前全写AND就完成复合查询了,我还没搞多关键词OR的那种):


     1 /// <summary>
     2 /// 构造函数使用True时:单个AND有效,多个AND有效;单个OR无效,多个OR无效;混合时写在AND后的OR有效
     3 /// 构造函数使用False时:单个AND无效,多个AND无效;单个OR有效,多个OR有效;混合时写在OR后面的AND有效
     4 /// </summary>
     5 public static class PredicateExtensions
     6 {
     7     public static Expression<Func<T, bool>> True<T>() { return f => true; }
     8 
     9     public static Expression<Func<T, bool>> False<T>() { return f => false; }
    10 
    11     public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
    12     {
    13         var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
    14 
    15         return Expression.Lambda<Func<T, bool>>(Expression.Or(expression1.Body, invokedExpression), expression1.Parameters);
    16     }
    17 
    18     public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
    19     {
    20         var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
    21 
    22         return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
    23     }
    24 }
  • 相关阅读:
    PostgreSQL管理工具:pgAdminIII
    PostgresQL7.5(开发版)安装与配置(win2003测试通过)
    让PosggreSQL运行得更好
    在.NET程序中使用PIPE(管道技术)
    在浏览网页过程中,单击超级链接无任何反应
    字符串转换
    数组初始化
    使用现有的COM
    后台服务程序开发模式(一)
    COM的四本好书
  • 原文地址:https://www.cnblogs.com/mindyou44/p/2818297.html
Copyright © 2011-2022 走看看