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; }

特性约束
    应用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, }

当然我们该有我们的查询方式(且和或)的约束,这就放上来

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

这样就构成了我们的查询约束,一般情况下,当前表字段查询的话我们只要属性名和表字段名一直即可,例如查询用户表的下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; } }

现在我们就可以进行查询了,如下(留意这句,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();
}

放个以前的效果图

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

超简单的集成表达式树查询组件,Sy.ExpressionBuilder 使用说明的更多相关文章

  1. 将简单的lambda表达式树转为对应的sqlwhere条件

    1.Lambda的介绍 园中已经有很多关于lambda的介绍了.简单来讲就是vs编译器给我带来的语法糖,本质来讲还是匿名函数.在开发中,lambda给我们带来了很多的简便.关于lambda的演变过程可 ...

  2. 利用 DynamicLinq 实现简单的动态表达式构建查询

    平时使用 LINQ 进行一些简单的条件拼接查询一般都会这样操作: public class SearchInputDto { public string ConditionA { get; set; ...

  3. ORM动态表达式树查询

    前言 接口获取参数后,创建返回值模型的条件表达式作为参数,传入使用依赖注入实例化后的业务层. 业务层创建返回值模型的IQUERY后,再使用参数条件表达式.最后进行延迟查询. 代码实现 参数模型Demo ...

  4. C#编程(六十六)----------表达式树总结

    表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代码之前修改或转换此代码,那么它是很有用的.有其是当你要将C#代码----如LINQ查询表达式转换成其他代码在另一个程 ...

  5. C#高级编程六十六天----表达式树总结【转】

    https://blog.csdn.net/shanyongxu/article/details/47257139 表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代 ...

  6. 转载:C#特性-表达式树

    原文地址:http://www.cnblogs.com/tianfan/ 表达式树基础 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要有普通 ...

  7. C#特性-表达式树

    表达式树ExpressionTree   表达式树基础 转载需注明出处:http://www.cnblogs.com/tianfan/ 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希 ...

  8. 表达式树ExpressionTree

    表达式树基础 转载需注明出处:http://www.cnblogs.com/tianfan/ 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要 ...

  9. asp.net core 排序过滤分页组件:sieve(2)表达式树的复习

    在Sieve组件中使用了很多关于表达式树的知识,但在我们日常的工作中写表达式树的机会是非常少的,至少在我的编程生涯中没怎么写过表达式树(可能也就是3,4次).所以,为了能够看懂Sieve里面的源代码, ...

随机推荐

  1. 线程池之 newSingleThreadExecutor 介绍

    package com.aaa.threaddemo; import java.text.DateFormatSymbols; import java.util.concurrent.Executor ...

  2. 关于老Windows平板电脑睡眠状态下无法开机(睡死)的问题及解决方案

    1.简述 前几天我从闲鱼上淘了一个二手Windows平板, 拿来上课记笔记用. 型号是联想的Thinkpad Helix 2nd, 2015年出产. cpu是酷睿m-5y71超低功耗处理器, TDP只 ...

  3. LockSupport、wait()、notify()

    LockSupport 名词解释 LockSupport是一个在JUC包里的线程阻塞工具类,所有的方法都是静态方法,主要用途是让线程在任意位置阻塞,广泛应用在AQS和各种JUC的锁中. 代码 publ ...

  4. 异步回调实现- Guava Retryer

    为什么要使用重试利器Retryer 在实际开发中我们经常会遇到需要轮询查询一个接果,实现轮询的方式有很多种,我们经常要写许多代码,有时还会怕写出的代码有bug,如果已经有轮子了,我们就没必要重复造轮子 ...

  5. ittun.com的使用方法

    [如果这篇文章对你有所作用,请加关注哦!] 步骤一: 进入官网http://ittun.com/ Windows 64位下载http://ittun.com/upload/17.2/ittun_win ...

  6. HDU3315 费用流

    为了不让颓影响到学习= = (主要是颓得不想敲代码) 所以,决定在OJ上随便挑一题,能搞便搞,不会就找题解,扒过来,认真研究......(比如这题 原帖:http://m.blog.csdn.net/ ...

  7. MySQL 日志管理及备份与恢复

    MySQL 日志管理及备份与恢复 1.日志管理 2.备份与恢复 1.日志管理: MySQL的默认日志保存位置为/usr/local/mysql/data 日志开启方式有两种:通过配置文件或者是通过命令 ...

  8. 我的新书——《PHP程序员面试笔试宝典》

    你好,是我琉忆. 一个文艺的PHP开发工程师. 很荣幸能够在这里带来我的第一本新书--<PHP程序员面试笔试宝典>. 一.创作过程 <PHP程序员面试笔试宝典>是我的第一本书, ...

  9. 微服务从代码到k8s部署应有尽有系列(二、网关)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  10. Spring Boot 自动配置(基本配置)

    在关于Spring Boot的第一篇中就提到了其几大特性,其中关于Java配置简化属性注入在上一篇SpringBoot外部配置 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中已经介绍. ...