• 超简单的集成表达式树查询组件,Sy.ExpressionBuilder 使用说明


        Sy.ExpressionBuilder是一套依赖于表达式树上的集成的查询组件。设计的初衷没别的,就为了少写代码,让查询业务可以变得更加模式化。可以从nuget 获取到该组件。

        来到查询,查询实体需要继承  QueryPageModel或者 QueryModel,从名字也基本可以看出来,一个用于分页,一个无分页,你可以根据自己需求选用哪个方式,如下我选了带分页的方式。

    public partial class AllManagerDto:QueryPageModel

       这样这个查询实体就拥有了我们这个插件的大多数功能。

        属性名称约束
        为了方便处理各种属性类型,我做了一些属性名称的约定。 

        时间范围查询 =>属性名称 以  Start,End 结尾 ,生成条件为 >= 和<=。
        数字范围查询 =>属性名称 以  Min,Max 结尾 ,生成条件为 >= 和<=。
        字符串查询 => 名字需要和表字段一致,生成条件为  Contains。

        编号查询必须是以Id结尾,不然如果编号为字符串的话,查询方式会以Contains形式查询。

        
        例如:

     /// <summary>
            /// 租户编号
            /// </summary>
            public virtual int? TenantIdMin { get; set; }
            /// <summary>
            /// 租户编号
            ///</summary>
            public virtual int? TenantIdMax { get; set; }
            /// <summary>
            /// 创建时间
            /// </summary>
            public virtual DateTime? CreateTimeStart { get; set; }
            /// <summary>
            /// 创建时间
            ///</summary>
            public DateTime? CreateTimeEnd { get; set; }
            /// <summary>
            /// 创建人编号
            /// </summary>
            public virtual string? CreateUserId { get; set; }
    View Code

        特性约束
        应用ConditionAttribute 特性,参数为 (字段名称,条件,查询方式)  目前我定义了常用的范围的约束。范围类型枚举       

    /// <summary>
        /// 高级搜索条件
        /// </summary>
        [Description("高级搜索条件")]
        public enum EnumCondition
        {
            /// <summary>
            /// 包含
            /// </summary>
            [Description("包含")]
            Contains = 0,
    
            /// <summary>
            /// 等于
            /// </summary>
            [Description("等于")]
            Equal = 1,
    
            /// <summary>
            /// 大于等于
            /// </summary>
            [Description("大于等于")]
            GtEqual = 2,
    
            /// <summary>
            /// 大于
            /// </summary>
            [Description("大于")]
            Gt = 3,
    
            /// <summary>
            /// 小于等于
            /// </summary>
            [Description("小于等于")]
            LtEqual = 4,
    
            /// <summary>
            /// 小于
            /// </summary>
            [Description("小于")]
            Lt = 5,
    
    
            /// <summary>
            /// 不等于
            /// </summary>
            [Description("不等于")]
            NotEqual = 6,
    
    
            /// <summary>
            /// SQL(In函数)
            /// </summary>
            [Description("SQL In")]
            In = 7,
    
            /// <summary>
            /// 在什么之间
            /// </summary>
            [Description("在什么之间")]
            Between = 8,
    
            /// <summary>
            /// 不包含
            /// </summary>
            [Description("不包含")]
            NotContain = 9,
    
            /// <summary>
            /// 从尾部匹配
            /// </summary>
            [Description("从尾部匹配")]
            EndsWith = 10,
    
            /// <summary>
            /// 从头部匹配
            /// </summary>
            [Description("从头部匹配")]
            StartsWith = 11,
    
            /// <summary>
            /// 不在范围内
            /// </summary>
            [Description("不在范围内")]
            NotIn = 12,
    
            /// <summary>
            /// 空的
            /// </summary>
            [Description("空的")]
            IsEmpty = 13,
    
            /// <summary>
            /// 不为空的
            /// </summary>
            [Description("不为空的")]
            IsNotEmpty = 14,
    
            /// <summary>
            /// 非Null的
            /// </summary>
            [Description("非Null的")]
            IsNotNull = 15,
    
            /// <summary>
            /// Null的
            /// </summary>
            [Description("Null的")]
            IsNull = 16,
    
            /// <summary>
            /// IsNullOrWhiteSpace
            /// </summary>
            [Description("IsNullOrWhiteSpace")]
            IsNullOrWhiteSpace = 17,
    
            /// <summary>
            /// IsNotNullNorWhiteSpace
            /// </summary>
            [Description("IsNotNullNorWhiteSpace")]
            IsNotNullNorWhiteSpace = 18,
    
            /// <summary>
            /// 
            /// </summary>
            [Description("枚举")]
            HasFlag = 19,
    
        }
    View Code

       当然我们怎么会少得了查询方式(且和或)的约束,这就放上来

      /// <summary>
        /// 当前条件所属类型
        /// </summary>
        [Description("当前条件所属类型")]
        public enum EnumConditionType
        {
            /// <summary>
            ////// </summary>
            [Description("")]
            And = 0,
    
            /// <summary>
            ////// </summary>
            [Description("")]
            Or = 1
        }
    View Code

      这样就构成了我们的查询约束,一般情况下,当前表字段查询的话我们只要属性名和表字段名一直即可,例如查询用户表的下UserName,如下即可

        /// <summary>
        /// 用户名称
        /// </summary>
        public string? UserName { get; set; }

      如果有那种不想暴露字段在外部的,这时我们的特性才会说显示出用户,例如我还是要查询UserName,但是暴露给前端的名称确是Uname,因为特性中的属性名优先级会高于查询模型中的名称,那我们可如下处理

       [Condition("UserName", EnumCondition.Contains,EnumConditionType.And)]
        public string?Uname { get; set; }

     又或者我们的某个字段需要包含一个集合的情况,我们可以如下实现(传过来的是用逗号分隔如:1,2,5,6)

       [Condition("UserId",EnumCondition.In,EnumConditionType.And)]
       public string?UserIds{ get; set; }

     导航属性单个查询,例如我在用户表,要根据角色名称查询,我们只要如下定义即可(导航属性名【角色表】+“.”+角色表下的角色名称,注意这个英文的 .,这个才是精髓)

    [Condition($"{nameof(Role)}.{nameof(Role.RoleName)}", EnumCondition.Contains,EnumConditionType.And)] 
    public string? RoleName { get; set; }

     导航属性集合查询,例如我在角色表,要查询有分配用户名字叫老王的所有角色,我们只要如下定义即可(导航属性名+“[”+角色表下的角色名称+"]",注意这个英文的 [], [] 表示这个是个集合)
       

    [Condition("Users[UserName]", EnumCondition.Contains,EnumConditionType.And)] 
    public string? UserName{ get; set; }

     特别说明,该组件还支持位移枚举的查询,使用也超级简单,和一般属性几乎无差,查询模型中如下定义即可。

    /// <summary>
    /// 性别
    /// </summary>
     public EnumGender? Gender { get; set; }

    不参与查询特性

       如果我们有个别参数是作用于别的用途,不直接参数查询,或者目前该插件处理不了的,我们可以通过该特性排除,如下使用
     

      /// <summary>
      /// 不参与查询
      /// </summary>
      [NotQuery]
      public string TreeId { get; set; }

     

    时间范围特性(2022年3月21号加)
      当限制用户查询时间范围的时候用,方式如下(特性只用加一个,EnumTimeType 有年月日 时 多种类型可以选择)

    复制代码
            /// <summary>
            /// 创建时间 开始
            /// </summary>
            [TimeSpan(4,EnumTimeType.Day)]
            public DateTime? CreateTimeStart { get; set; }
    
            /// <summary>
            /// 创建时间  结束
            /// </summary>
            public DateTime? CreateTimeEnd { get; set; }
    复制代码

     

    额外扩展
      对于排序,有些情况要做到用户点击表头,然后由后端进行排序后返回,这里我也预留了空间,如下(input 为继承了:QueryPageModel 的模型),第一个参数表示 要排序的字段名,第二个参数true 表示倒序,false 表示正序。

     

     input.AddOrderByItem(nameof(News.Id),true);

    我还加了一个相对显得鸡肋的默认排序(强迫症喜欢有个默认的),如果前端有传排序过来的话,这个是无效的,使用方式如下:

    input.DefaultOrderBy(nameof(News.CreateTime)

     

    当我们了解了以上约定,我们定义一个相对完整的查询模型,如下

     /// <summary>
        /// 查询参数实体
        /// </summary>
    
        public class AllManagerDto : QueryPageModel
        {
            /// <summary>
            /// 创建时间 开始(时间必须以Start结尾)
            /// </summary>
            public DateTime? CreateTimeStart { get; set; }
    
            /// <summary>
            /// 创建时间  结束(结束时间必须以End结尾)
            /// </summary>
            public DateTime? CreateTimeEnd { get; set; }
          
            /// <summary>
            /// 角色编号
            /// </summary>
            [Condition("Role.Id", EnumCondition.In)]
            public string RoleId { get; set; }
    
            /// <summary>
            /// 角色名称
            /// </summary>
    
            [Condition("Role.RoleName", EnumCondition.Contains)]
    
            public string RoleName { get; set; }
    
    
            /// <summary>
            /// 系统名称
            /// </summary>
    
            [Condition("Sys[SysName]", EnumCondition.Contains)]
    
            public string SysName { get; set; }
    
    
            /// <summary>
            /// 名称
            /// </summary>
            public string UserName { get; set; }
    
    
            /// <summary>
            /// 性别
            /// </summary>
    
            public EnumGender? Gender { get; set; }
    
    
            [NotMapped]
            public string TreeId { get; set; }
    
            /// <summary>
            /// 年龄 开始(必须以Min结尾)
            /// </summary>
            public int? AgeMin { get; set; }
    
            /// <summary>
            /// 年龄  结尾(必须以Max结尾)
            /// </summary>
            public int? AgeMax{ get; set; }
     
    
    
        }
    View Code

    现在我们就可以进行查询了,如下(留意这句,input.ToExpression<Manager>() 主要是这句把查询参数转换成表达式了)

    复制代码
           /// <summary>
            /// 查询
            /// </summary>
            /// <param name="input"></param>
            /// <returns></returns>
            public static List<Manager> GetAll(AllManagerDto input)
            {
                var list = GetList();
                input.RoleId = "1";
                input.Tel = "18888888888";
                input.UserName = "张三";
                input.Gender = EnumGender.Man;
                input.CreateTimeStart = DateTime.Parse("2021-9-22");
                var query = input.ToExpression<Manager>();
                return list.AsQueryable().Where(query).ToList();
            }
    复制代码

    放个以前的效果图

     后续有扩展,会在这里加.....

     好了,到这你又可以去撸代码了。

        

        

     

  • 相关阅读:
    Ideal maven自己配置的本地仓库无效问题解决
    pycharm访问远程GPU服务器终端并使用Tmux终端复用器
    题目0095-删除指定目录
    宁愿“大小周”、每天只写 200 行代码、月薪 8k-17k 人群再涨 | 揭晓中国开发者真实现状
    对话张璐:硅谷正在追逐两大赛道创新,融资降温但技术商业化更快了
    基于元数据的无代码平台设计与开发概述
    【计算机网络】UDP协议编写群聊天室----附代码
    学会这几款表白特效让你明年双十一不再是一个人
    了解XSS攻击与CSRF攻击
    CleanMyMac X果粉装机必备MAC软件 Macbook的垃圾清理工具
  • 原文地址:https://www.cnblogs.com/noert/p/15968706.html