如何在代码里优雅的拼接SQL

刚进入这行业的时候,最早的时候用ADO,后来又出了各种ORM,在用了很多年后,还是觉得手写SQL最舒服,也最灵活。在各种对比后本人选择了Dapper,选择的理由是够轻量,性能好。

不管你用什么数据库框架,都会涉及到拼接SQL,可能你会说EF里不用拼接SQL,那你也得组装Expression对吧

不管你用什么工具,肯定避不开的一个就是拼接SQL,如果遇到稍复杂的逻辑,拼接SQL就很乱,可读性非常的差,如下:

//比较常见的拼接方式
var name = "jason";
var gender = 1;
var age = 18;
var sql = new StringBuilder("select * from tb where 0 = 0");
if (!string.IsNullOrWhiteSpace(name))
    sql.Append(" and name=@name");
if (gender > 0)
    sql.Append(" and gender=@gender");
if (age > 0)
    sql.Append(" and age=@age");

或者

 var name = "jason";
 var gender = 1;
 var age = 18;
 var sql = $"select * from tb where 0=0 {(!string.IsNullOrWhiteSpace(name) ? " and name=@name" : "")} {(age > 0 ? " and age=@age" : "")} {(gender > 0 ? " and gender=@gender" : "")}";

我相信上面的写法很多人都写过,我也这么写了很多年,当你遇到比较复杂的逻辑时,这种写法可读性非常的差,别特是条件非常多的时候。后来我就想有没有什么方式,既能灵活的拼接,又有很好的可读性呢?如果要有很好的可读性,那么SQL的拼接不能放在多个条件里拼接,看到的就是一条完整的SQL语句。思考后,我写一个扩展方法,先看如何使用

var sql="select * from tb where 0=0 {and name=@name} {and gender=@gender} {and age=@age}".Splice(!string.IsNullOrWhiteSpace(name),gender>0,age>0);

用法其实有点像string.Format,每一对大括号里的字符串,是否需要,根据Splice里的对应的第几个参数是一一对应的,你看见的SQL是一个完整的SQL语句,并且支持if…else:

var status=false;
var sql="select * from tb where status={1:0}".Splice(status);
//拼出的sql为:select * from tb where status=0

大括号内,用冒号分开,当对应参数为True时,将使用冒号前面部分,否则使用冒号的后面部分

您已经看到这里了,您觉得这样拼接是否是比上面的方式更具有可读性呢?

下面直接上实现代码,非常简单

public static string Splice(this string sql, params bool[] conditions)
{
     var startIndex = 0;
     foreach (var condition in conditions)
     {
         var start = sql.IndexOf('{', startIndex);
         if (start < 0)
             return sql;
         var end = sql.IndexOf('}', start);
         if (end < 0)
             return sql;
         startIndex = end;

         var elseIndex = sql.IndexOf(':', start, end - start);
         if (elseIndex < 0)
         {
             if (condition)
             {
                 sql = sql.Remove(start, 1).Remove(end - 1, 1);
                 startIndex -= 2;
             }
             else
             {
                 var count = end - start + 1;
                 sql = sql.Remove(start, count);
                 startIndex -= count;
             }
         }
         else
         {
             if (condition)
             {
                 var count = end - elseIndex + 1;
                 sql = sql.Remove(start, 1).Remove(elseIndex - 1, count);
                 startIndex -= count;
             }
             else
             {
                 var count = elseIndex - start + 1;
                 sql = sql.Remove(start, count).Remove(end - count, 1);
                 startIndex -= count;
             }
         }
     }
     return sql;
 }

也许您觉得条件多了,可读性也不好,第几个参数对应到的第几个{}呢?是的,确实有这个问题存在,所以我写了一个vsix插件,可以把对应的拼接部分高亮:高亮效果
在扩展市场里搜索 SQLSpliceHighlight 安装即可,本人不太熟悉vsix的开发,目前此扩展支持还不是特别好,后面会慢慢完善,如果您熟悉的话可以帮我完善一下插件。

本人对Dapper进行了封装,支持不同数据库,集成了缓存支持,性能监控,也集成了上面的拼接方法,GitHub库:
https://github.com/1100100/Dapper.Extensions
如果您有更好的拼接方式,欢迎分享出来,如果您会开发VSIX扩展,可以提一个PR,感谢您的阅读。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值