致掣 发表于 2025-5-30 14:35:45

ShadowSql之表达式树

ShadowSql的主要思想通过表和字段的影子来拼写sql
.net中的表达式树是作为模型类和查询逻辑的影子,非常契合ShadowSql
拿表达式树来拼写sql就和EF类似
 
一、nuget包
nuget安装ShadowSql.Expressions
引用命名空间: ShadowSql.Expressions
 
二、使用用法
1. 表达式查询
1.1 按常量查询
var query = new TableSqlQuery<User>("Users")
    .Where(u => u.Name == "张三");
// SELECT * FROM WHERE ='张三'1.2 按参数查询
var query = new TableSqlQuery<User>()
    .Where<UserParameter>((u, p) => u.Age > p.Age2);
// SELECT * FROM WHERE >@Age2 注: TableSqlQuery不传参数tableName会以类名为表名
 2. 表达式排序
2.1 对单个字段排序
var cursor = new Table("Users")
    .Take<User>(10)
    .Asc(u => u.Id);
// SELECT TOP 10 * FROM ORDER BY 2.2 对多个字段排序
var cursor = new Table("Users")
    .Take<User>(10)
    .Desc(u => new { u.Age, u.Id });
// SELECT TOP 10 * FROM ORDER BY DESC, DESC 
3. 联表查询
3.1 主外键联表
var query = new Table("Users")
    .SqlJoin<User, UserRole>(new Table("UserRoles"))
    .On(u => u.Id, r => r.UserId);
// SELECT * FROM AS t1 INNER JOIN AS t2 ON t1.=t2.3.2 逻辑表达式联表
var query = new Table("Users")
    .SqlJoin<User, UserRole>(new Table("UserRoles"))
    .On((u, r) => u.Id == r.UserId);
// SELECT * FROM AS t1 INNER JOIN AS t2 ON t1.=t2. 
4. 插入
4.1 插入常量值
var insert = new Table("Users")
    .ToInsert(() => new User { Name = "张三", Age = 18 });
// INSERT INTO (,)VALUES('张三',18)4.2 插入参数
var insert = new Table("Users")
    .ToInsert<UserParameter, User>(p => new User { Name = p.Name2, Age = p.Age2 });
// INSERT INTO (,)VALUES(@Name2,@Age2) 
5. 表达式删除
var delete = new TableSqlQuery<Student>("Students")
    .Where(s => s.Score < 60)
    .ToDelete();
// DELETE FROM WHERE <606.2 参数化更新
var update = new Table("Users")
    .ToUpdate<User>(u => u.Id == 1)
    .Set(u => new User { Age = 18 });
// UPDATE SET =18 WHERE =16.3 原值叠加更新
var user = new User { Id =1, Age = 18 };
var update = EmptyTable.Use("Users")
    .ToUpdate<User>(u => u.Id == user.Id)
    .Set(u => new User { Age = user.Age });
// UPDATE SET =@Age WHERE =@Id 
7、表达式获取数据

7.1 直接获取全表
var update = new Table("Students")
    .ToUpdate<Student>(u => u.Score < 60 && u.Score > 55)
    .Set(u => new Student { Score = u.Score + 5 });
// UPDATE SET =(+5) WHERE <60 AND >557.3 从查询表达式获取
var select = new Table("Users")
    .ToSelect<User>()
    .Select(u => new { u.Id, u.Name });
// SELECT , FROM 7.3 从表查询获取
var select = new Table("Users")
    .ToSelect<User>(u => u.Status)
    .Select(u => u.Id);
// SELECT FROM WHERE =17.4 分页获取
var select = new Table("Users")
    .ToSqlQuery<User>()
    .Where(u => u.Status)
    .ToSelect()
    .Select(u => new { u.Id, u.Name });
// SELECT , FROM WHERE =1 
三、实现方法
1. 解析表达式树
解析表达式树需要一些技巧,需要用到设计模式
1.1 Visitor解析CURD组件
  CURD中好些地方都可以用表达式树
      首先需要用到ExpressionVisitor类,这个类用到了访问者模式
   定义基类VisitorBase继承ExpressionVisitor,定义可能用到的一些方法,这个地方用到了模版方法设计模式
   实现SelectVisitor、UpdateVisitor、OrderByVisitor等
1.2  VisitSource表示数据源组件的能力和作用
  另外单表可以CURD,联表也可以CURD,分组还可以查询,就又抽象出表达式数据源
  数据源基类是VisitSourceBase,定义一些常用方法和必须的抽象方法也是模版方法设计模式
  实现TableVisitor、GroupByVisitor、JoinOnVisitor等
1.3 Visitor和VisitSource组合起来解析表达式树
  这样组合可以节省大量代码,这就是运用了桥接设计模式
      感兴趣的同学可以去查看源代码
 
四、参数化sql
ShadowSql对参数化查询支持的很好,本人也是非常推荐使用参数化查询
其一、参数化查询可以防sql注入
其二、参数化查询sql可以复用,可以考虑把参数化查询的sql缓存起来,用Dapper调用sql和参数对象直接执行
 
欢迎大家尝试,有什么问题给我留言,我会尽力满足大家的需求
 
源码托管地址: https://github.com/donetsoftwork/Shadow,也欢迎大家直接查看源码。
gitee同步更新:https://gitee.com/donetsoftwork/Shadow
文档地址: https://donetsoftwork.github.io/Shadow/expression/index.html
如果大家喜欢请动动您发财的小手手帮忙点一下Star。
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

驳嗦 发表于 2025-10-12 00:42:01

喜欢鼓捣这些软件,现在用得少,谢谢分享!

求几少 发表于 2025-11-26 15:17:58

前排留名,哈哈哈

明思义 发表于 2025-11-30 01:50:05

东西不错很实用谢谢分享

鞠古香 发表于 2025-11-30 10:56:15

喜欢鼓捣这些软件,现在用得少,谢谢分享!
页: [1]
查看完整版本: ShadowSql之表达式树