利用formatter原理自动化参数化查询
2018-06-17 22:50:44来源:未知 阅读 ()
前言:对于经常忙于服务端开发的小伙伴来说,与DB层打交道是在正常不过的事了,但是每次页面的查询条件新增往往意味着后端代码参数化同比增长,当然你可以不使用sqlhelper自带的参数化条件查询,可以直接传递参数,这样一来,可能你写的代码就变少了,但是存在一个隐藏的问题就是sql注入,对于sql注入我想大家都并不陌生,相关资源和预防措施网上千篇一律,有兴趣可以自己去了解,常用的注入工具是sqlmapper,有兴趣的可以一并去了解。
那么你写代码既要保持代码的优雅,语句条数的少量,有想要保证代码的安全性能,不被轻易注入,有没有一种2种都能兼容的方式呢,在对于一般习惯拘泥于原有代码思维的人来看,可能并没有,但是习惯于从不同角度思考问题的人来说,条条大路通罗马,比如我下面说的这种就是基于.NET 自带的stirngfromatter原理来实现的一种自动化参数化查询~~
由于口头表述不是很好,我直接贴图来说明了,请看
这是原先的参数化查询
1 public PayOrderEntity GetPayOrderInfoById(int id) 2 { 3 PayOrderEntity parorderModel = new PayOrderEntity(); 4 List<SqlParameter> paramList = new List<SqlParameter>(); 5 string sql = @"select p.Id as pid 6 ,c.Id 7 ,c.UserId 8 ,p.OrderId 9 ,p.TransactionId 10 ,p.PayType 11 ,c.TotalPrice as orderprice 12 ,p.TotalPrice as payprice 13 ,c.[Status] as orderstatus 14 ,p.[Status] as paystatus 15 ,c.CreateTime 16 ,p.PayTime 17 ,c.Remark as orderremark 18 ,p.Remark as payremark 19 from t_ContentOrder(nolock) c 20 left join t_Payment(nolock) p 21 on c.Id=p.OrderId where c.IsDeleted=0 and p.IsDeleted=0 and p.Id= {0}"; 22 paramList.Add(new SqlParameter("@id", id)); 23 try 24 { 25 var dt = SqlHelper.ExecuteDataset(write_connstring, CommandType.Text, sql, paramList.ToArray()); 26 27 //使用重写后的DB驱动查询方法调用 by:xuja 2017-05-27 10:34:19 28 //var dt = SqlQuery(sql, id); 29 30 31 parorderModel = DbTableConvertor<PayOrderEntity>.ConvertToEntity(dt.Tables[0]); 32 } 33 catch (Exception ex) 34 { 35 Core.Log.TraceLogger.Error(ex); 36 } 37 return parorderModel; 38 }
步骤一 先实例化一个sqlparams实体
步骤二 将满足条件的参数传入定义好的参数实体并赋值(可能需要条件验证)
步骤三 将填充完成后的参数对象传入调用的sqlhelper查询接口中
这样四步即可实现整个查询流程
看着流程也并不复杂,但是大家想过一个问题没,如果一个页面有6个以上的查询条件,是不是定义起来会很吃力,这种感觉我相信大家都会有,我也不列外 囧 ,接下来利用formatter原理我们在看看重构后的参数化查询代码
1 /// <summary> 2 /// sql参数自动化拼接方法 3 /// 创建人:xujiangan 4 /// 2017-05-27 10:35:40 5 /// </summary> 6 /// <param name="sqlCommand">需要查询的sql</param> 7 /// <param name="param">需要拼接的参数列表</param> 8 /// <returns></returns> 9 public Tuple<string, SqlParameter[]> ProcessSqlCommand(string sqlCommand, params object[] param) 10 { 11 var tempKVDic = param.Select((item, i) => new KeyValuePair<string, object>("@an" + i, item)).ToDictionary(k => k.Key, v => v.Value); 12 13 var tempSqlCommand = string.Format(sqlCommand, tempKVDic.Keys.ToArray()); 14 15 var tempParams = tempKVDic.Select(t => new SqlParameter(t.Key, t.Value)).ToArray(); 16 17 return Tuple.Create(tempSqlCommand, tempParams); 18 }
方法的返回值因为不确定到具体类型,所以用了元组来定义了,元组的能力类似于dynamic T类型,这里就不多介绍了,参数的条件只有2个,1.要执行查询的sql语句 2.需要传递的参数化条件
代码逻辑:1.将参数列表利用键值对的方法一一对应组合,参数可以自动增长,组成参数列表字典;2.使用format方法将sql语句和参数字典拼接;3.将拼接好的查询字符串返回给调用方
原先接口并没有这次参数条件的重载 接下来,我们还学要重写一下sqlhelper执行查询的接口,如下:
1 /// <summary> 2 /// 重写ExcuteQuery方法,便于自动话添加参数 3 /// 创建人:xujiangan 4 /// 2017-05-27 10:35:07 5 /// </summary> 6 /// <param name="sqlCommand">执行sql语句</param> 7 /// <param name="param">需要新增的查询参数</param> 8 /// <returns></returns> 9 public DataSet SqlQuery(string sqlCommand, params object[] param) 10 { 11 var dt = new DataSet(); 12 if (param == null || param.Length == 0) 13 { 14 dt = SqlHelper.ExecuteDataset(write_connstring, sqlCommand, CommandType.Text); 15 } 16 17 var temp = ProcessSqlCommand(sqlCommand, param); 18 19 dt = SqlHelper.ExecuteDataset(write_connstring, CommandType.Text, temp.Item1, temp.Item2); 20 21 //object entity = DbTableConvertor<object>.ConvertToEntity(dt.Tables[0]); 22 23 return dt; 24 }
代码大家都能看懂,无非就是有参和无参两种情况做了区分,我就不解释了...
俗话说,欲善其事,必先利其器,有了上面的准备之后,我们就可以调用我们刚才重写的接口啦
调用请看下面:
1 public PayOrderEntity GetPayOrderInfoById(int id) 2 { 3 PayOrderEntity parorderModel = new PayOrderEntity(); 4 string sql = @"select p.Id as pid 5 ,c.Id 6 ,c.UserId 7 ,p.OrderId 8 ,p.TransactionId 9 ,p.PayType 10 ,c.TotalPrice as orderprice 11 ,p.TotalPrice as payprice 12 ,c.[Status] as orderstatus 13 ,p.[Status] as paystatus 14 ,c.CreateTime 15 ,p.PayTime 16 ,c.Remark as orderremark 17 ,p.Remark as payremark 18 from t_ContentOrder(nolock) c 19 left join t_Payment(nolock) p 20 on c.Id=p.OrderId where c.IsDeleted=0 and p.IsDeleted=0 and p.Id= {0}"; 21 try 22 { 23 //使用重写后的DB驱动查询方法调用 by:xuja 2017-05-27 10:34:19 24 var dt = SqlQuery(sql, id); 25 parorderModel = DbTableConvertor<PayOrderEntity>.ConvertToEntity(dt.Tables[0]); 26 } 27 catch (Exception ex) 28 { 29 Core.Log.TraceLogger.Error(ex); 30 } 31 return parorderModel; 32 }
是不是发现少了什么?没错,我们此时不再需要定义繁杂的sqlparams对象拉,直接传递参数即可,有多少传多少,如果太多可以定义数组或者参数实体传递哦~
PS:注意sql代码语句中参数位置改为占位符!!!
到此为止,整个自动化参数化查询基本上就结束了,有问题可以给我留言指出,共勉
项目目前已经应用到 admin.kk.net 支付订单详情页面查询,经多番测试,并没有发现什么问题,看来是可以用的。
建议sql代码大小写一致,保持只解析一次。
高山仰止,景行行止
by:Jsonxu
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:CORS跨域请求C#版
- 利用python自动生成verilog模块例化模板 2019-08-13
- 文本分类问题相关原理知识 2019-07-24
- 原创:Python编写通讯录,支持模糊查询,利用数据库存储 2019-07-24
- 利用Python模拟登录pastebin.com 2019-07-24
- 利用切片赋值为空串达到删除列表值的目的 2019-07-24
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash