ShadowSql.net之表达式树

ShadowSql的主要思想通过表和字段的影子来拼写sql

.net中的表达式树是作为模型类和查询逻辑的影子,非常契合ShadowSql

拿表达式树来拼写sql就和EF类似

 

一、nuget包

nuget安装ShadowSql.Expressions

引用命名空间: ShadowSql.Expressions

 

二、使用用法

1. 表达式查询

1.1 按常量查询

?
1
2
3
var query = new TableSqlQuery<User>( "Users" )
     .Where(u => u.Name == "张三" );
// SELECT * FROM [Users] WHERE [Name]='张三'

1.2 按参数查询

?
1
2
3
var query = new TableSqlQuery<User>()
     .Where<UserParameter>((u, p) => u.Age > p.Age2);
// SELECT * FROM [User] WHERE [Age]>@Age2

 注: TableSqlQuery不传参数tableName会以类名为表名

 2. 表达式排序

2.1 对单个字段排序

?
1
2
3
4
var cursor = new Table( "Users" )
     .Take<User>(10)
     .Asc(u => u.Id);
// SELECT TOP 10 * FROM [Users] ORDER BY [Id]

2.2 对多个字段排序

?
1
2
3
4
var cursor = new Table( "Users" )
     .Take<User>(10)
     .Desc(u => new { u.Age, u.Id });
// SELECT TOP 10 * FROM [Users] ORDER BY [Age] DESC,[Id] DESC

 

3. 联表查询

3.1 主外键联表

?
1
2
3
4
var query = new Table( "Users" )
     .SqlJoin<User, UserRole>( new Table( "UserRoles" ))
     .On(u => u.Id, r => r.UserId);
// SELECT * FROM [Users] AS t1 INNER JOIN [UserRoles] AS t2 ON t1.[Id]=t2.[UserId]

3.2 逻辑表达式联表

?
1
2
3
4
var query = new Table( "Users" )
     .SqlJoin<User, UserRole>( new Table( "UserRoles" ))
     .On((u, r) => u.Id == r.UserId);
// SELECT * FROM [Users] AS t1 INNER JOIN [UserRoles] AS t2 ON t1.[Id]=t2.[UserId]

 

4. 插入

4.1 插入常量值

?
1
2
3
var insert = new Table( "Users" )
     .ToInsert(() => new User { Name = "张三" , Age = 18 });
// INSERT INTO [Users]([Name],[Age])VALUES('张三',18)

4.2 插入参数

?
1
2
3
var insert = new Table( "Users" )
     .ToInsert<UserParameter, User>(p => new User { Name = p.Name2, Age = p.Age2 });
// INSERT INTO [Users]([Name],[Age])VALUES(@Name2,@Age2)

 

5. 表达式删除

?
1
2
3
4
var delete = new TableSqlQuery<Student>( "Students" )
     .Where(s => s.Score < 60)
     .ToDelete();
// DELETE FROM [Students] WHERE [Score]<60

 

6. 表达式更新


6.1 常量更新

?
1
2
3
4
var update = new Table( "Users" )
     .ToUpdate<User>(u => u.Id == 1)
     .Set(u => new User { Age = 18 });
// UPDATE [Users] SET [Age]=18 WHERE [Id]=1

6.2 参数化更新

?
1
2
3
4
5
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 [Users] SET [Age]=@Age WHERE [Id]=@Id

6.3 原值叠加更新

?
1
2
3
4
var update = new Table( "Students" )
     .ToUpdate<Student>(u => u.Score < 60 && u.Score > 55)
     .Set(u => new Student { Score = u.Score + 5 });
// UPDATE [Students] SET [Score]=([Score]+5) WHERE [Score]<60 AND [Score]>55

 

7、表达式获取数据


7.1 直接获取全表

?
1
2
3
4
var select = new Table( "Users" )
     .ToSelect<User>()
     .Select(u => new { u.Id, u.Name });
// SELECT [Id],[Name] FROM [Users]

7.3 从查询表达式获取

?
1
2
3
4
var select = new Table( "Users" )
     .ToSelect<User>(u => u.Status)
     .Select(u => u.Id);
// SELECT [Id] FROM [Users] WHERE [Status]=1

7.3 从表查询获取

?
1
2
3
4
5
6
var select = new Table( "Users" )
     .ToSqlQuery<User>()
     .Where(u => u.Status)
     .ToSelect()
     .Select(u => new { u.Id, u.Name });
// SELECT [Id],[Name] FROM [Users] WHERE [Status]=1

7.4 分页获取

?
1
2
3
4
5
6
7
var select = new Table( "Users" )
     .ToSqlQuery<User>()
     .Where(u => u.Status)
     .Take(10, 20)
     .Desc(u => u.Id)
     .ToSelect();
// SELECT * FROM [Users] WHERE [Status]=1 ORDER BY [Id] OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY

 

三、实现方法

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。

 

原创作者: xiangji 转载于: https://www.cnblogs.com/xiangji/p/18901576
资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 在网页设计中,为图片添加文字是一种常见的需求,用于增强视觉效果或传达更多信息。本文将介绍两种常用的方法:一种是将图片设置为背景并添加文字;另一种是利用<span>标签结合CSS定位来实现。 这种方法通过CSS实现,将图片设置为一个容器(通常是<div>)的背景,然后在容器中添加文字。具体步骤如下: 创建一个包含文字的<div>元素: 使用CSS设置<div>的背景图片,并调整其尺寸以匹配图片大小: 如有需要,可使用background-position属性调整图片位置,确保文字显示在合适位置。这样,文字就会显示在图片之上。 另一种方法是将文字放在<span>标签内,并通过CSS绝对定位将其放置在图片上。步骤如下: 创建一个包含图片和<span>标签的<div>: 设置<div>为相对定位,以便内部元素可以相对于它进行绝对定位: 设置<span>为绝对定位,并通过调整top和left属性来确定文字在图片上的位置: 这种方法的优点是可以精确控制文字的位置,并且可以灵活调整文字的样式,如颜色和字体大小。 两种方法各有优势,可根据实际需求选择。在实际开发中,还可以结合JavaScript或jQuery动态添加文字,实现更复杂的交互效果。通过合理运用HTML和CSS,我们可以在图片上添加文字,创造出更具吸引力的视觉效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值