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

博客 动态
0 133
羽尘
羽尘 2022-03-07 10:56:14
悬赏:0 积分 收藏

超简单的集成表达式树查询组件,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; }

 又或者我们的某个字段需要包含一个集合的情况,我们可以如下实现

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

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

   [Condition("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; }

额外扩展
  对于排序,有些情况要做到用户点击表头,然后由后端进行排序后返回,这里我也预留了空间,如下(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.ToQueryModel<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.ToQueryModel<Manager>();            return list.AsQueryable().Where(query).ToList();        }

放个以前的效果图

 

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

    

    

 

posted @ 2022-03-07 10:44 noert 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    羽尘

    羽尘 (王者 段位)

    2335 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员