ShadowSql
- 一个.net sql拼写工具
- 通过扩展Dapper实现ORM
- 对标开源项目SqlKata
一、五个子项目
- .net拼接sql工具
- 支持多种数据库,包括MsSql,MySql,Oracle,Sqlite,Postgres等
- 整个sql拼写只使用1个StringBuilder,减少字符串碎片生成
- Nuget包名: ShadowSql.Core
- 精简版
- .net拼接sql工具
- 支持多种数据库,包括MsSql,MySql,Oracle,Sqlite,Postgres等
- 整个sql拼写只使用1个StringBuilder,减少字符串碎片生成
- 易用版
- ShadowSql.Core的Dapper扩展
- 用于执行ShadowSql.Core拼接的sql
- Nuget包名: ShadowSql.Dapper.Core
- 精简版
- ShadowSql的Dapper扩展
- 用于执行ShadowSql拼接的sql
- Nuget包名: ShadowSql.Dapper
- 易用版
- 用于拼写DDL的sql语句,主要是CreateTable
- 搭配Dapper.Shadow可以实现执行DDL操作
二、对标开源项目SqlKata
1、拼接sql从头到尾只使用一个StringBuilder
1.1 ShadowSql通过StringBuilder拼接
- 拼接sql继承接口ISqlFragment和ISqlEntity
- 对同一个StringBuilder对象进行操作
public interface ISqlFragment {
/// <summary>
/// sql拼接
/// </summary>
/// <param name="engine">数据库</param>
/// <param name="sql">sql</param>
/// <returns></returns>
bool TryWrite(ISqlEngine engine, StringBuilder sql);
}
public interface ISqlEntity {
/// <summary>
/// sql拼接
/// </summary>
/// <param name="engine">数据库</param>
/// <param name="sql">sql</param>
void Write(ISqlEngine engine, StringBuilder sql);
}
1.2 SqlKata通过string拼接
- SqlKatat通过Replace、Concat和Join等进行sql拼接
protected virtual string CompileConditions(SqlResult ctx, List<AbstractCondition> conditions) {
var result = new List<string>();
for (var i = 0; i < conditions.Count; i++) {
var compiled = CompileCondition(ctx, conditions[i]);
if (string.IsNullOrEmpty(compiled))
continue;
var boolOperator = i == 0 ? "" : (conditions[i].IsOr ? "OR " : "AND ");
result.Add(boolOperator + compiled);
}
return string.Join(" ", result);
}
public static string ReplaceIdentifierUnlessEscaped(this string input, string escapeCharacter, string identifier, string newIdentifier) {
var nonEscapedRegex = new Regex($@"(?<!{Regex.Escape(escapeCharacter)}){Regex.Escape(identifier)}");
var nonEscapedReplace = nonEscapedRegex.Replace(input, newIdentifier);
var escapedRegex = new Regex($@"{Regex.Escape(escapeCharacter)}{Regex.Escape(identifier)}");
return escapedRegex.Replace(nonEscapedReplace, identifier);
}
2、执行更快、内存消耗更少
2.1 简单查询对比
- 简单查询对比
- SqlKata耗时是TableName的20倍多
- SqlKata耗时是SqlQuery的33倍
- Logic性能最好,SqlKata耗时是他的50倍
- SqlKata内存消耗也是3种的10多倍以上
Method |
Mean |
Error |
StdDev |
Ratio |
Gen0 |
Gen1 |
Allocated |
Alloc Ratio |
ShadowSqlByTableName |
220.64 ns |
2.883 ns |
3.205 ns |
0.05 |
0.0955 |
- |
1656 B |
0.13 |
ShadowSqlBySqlQuery |
115.90 ns |
0.638 ns |
0.709 ns |
0.03 |
0.0530 |
- |
920 B |
0.07 |
ShadowSqlByLogic |
69.81 ns |
1.259 ns |
1.450 ns |
0.02 |
0.0330 |
- |
576 B |
0.05 |
SqlKataBench |
4,173.57 ns |
24.612 ns |
28.343 ns |
1.00 |
0.7365 |
0.0040 |
12712 B |
1.00 |
三、本项目的特点
1、支持影子编程
- 通过自定义表(及其列)作为实际数据表(或模型类)的影子
- 自定义表(及其列)可以实现绝大多数sql的拼写
- 通过查看引用可以定位到使用到该表或该字段的所有sql
- 重构时查看字段引用可以准确评估影响范围
- 删除字段相应sql拼写方法编译失败,按图索骥可以快速完成重构
- 修改字段名相应sql可以同步重构完成
- 也就是可实现编译检测的sql拼写
2、通用轻量级
- 跨平台,支持net7.0;net8.0;net9.0;netstandard2.0;netstandard2.1
- 支持多种数据库(MsSql,MySql,Oracle,Sqlite,Postgres等),可扩展其他数据库方言的支持
- 本工具很小、且不依赖第三方包
3、高性能
- 拼写sql耗时更少
- 拼写sql内存消耗更少
- 拼写sql方便直接对接Dapper,使用Dapper高效执行sql
4、简便易用
- 能快速上手
- 大多数API和sql一致,代码可读性强,使用简单
- 支持链式语法,大多数功能可以直接一行代码搞定