我手头有个古老的项目,持久层用的是古老的ADO.net。前两天去昆明旅游,其中的一个景点是云南民族村,通过导游介绍知道了一个古老的民族——基诺族,“基”在这个族内代表舅舅,“基诺”意为“跟在舅舅后边”,加以引申即为“尊崇舅舅的民族”,很有意思吧,这是我国最后一个被发现并确认下来的少数民族,即第56个民族。  项目里的ado.net和基诺族一样古老。

话说,项目里数据访问层,好多都是拼的sql,这给sql注入提供了可乘之机,为了系统安全,决定在有限的时间内,将它改成参数化。

其中,有个根据多个订单号查询支付单的方法,签名如下:

public DataTable GetAlipayNotifyRecords(AlipayPaymentStatus status, params string[] trade_no)

那么,问题来了,因为sql里有in, 而 in(@no)的方式是行不通的。

怎么办呢?  首先想到的是对参数做处理:

public DataTable GetAlipayNotifyRecords(AlipayPaymentStatus status, params string[] trade_no)
{
string sql = @"select * from T_AlipayNotityRecord where trade_status=@trade_status and trade_no in(@trade_no)";
//string inValue = "'" + string.Join("','", trade_no) + "'";//= string.Join(",", trade_no)
string inValue = "";
trade_no.ToList().ForEach(no => inValue += " union all select '" + no+"'");
inValue = inValue.Substring(" union all".Length);
List<SqlParameter> paramList = new List<SqlParameter>()
{
new SqlParameter("@trade_status",status.ToString()),
new SqlParameter("@trade_no",inValue),
};
var ds = SqlHelper.SqlDataSet(ConfigFile.PayCenterConnection, sql, CommandType.Text, paramList.ToArray());
if (ds == null || ds.Tables.Count == )
return null;
return ds.Tables[];
}

经测试,无效。经分析可知,sqlhelper会把你参数值当成字符串,不会对其做转义。所以,不管怎么对参数值处理,都还是一串字符串。

按这样的原理往下想,只能是将单号分开来传递给sql了。那么正好sql的in可以通过如下几种方式等效实现:

  • sql里有临时表,可以in一个临时表--这时,可以考虑and trade_no in(select @p1 union all select @p2 union all...)的方式
  • 把sql的in集合,转换为一个用or拼接起来的集合---即,and (trade_no=@p1 or trade_no=@p2 or trade_no=@p3 or...)

如下代码是按照后者的思路解决了这个问题:

public DataTable GetAlipayNotifyRecords(AlipayPaymentStatus status, params string[] trade_no)
{
string sql = @"select * from T_AlipayNotityRecord where trade_status=@trade_status and ({0})"; List<SqlParameter> paramList = new List<SqlParameter>()
{
new SqlParameter("@trade_status",status.ToString()),
};
string sql1 = "";
for (int i=;i<trade_no.Length;i++)
{
sql1 += " or trade_no=@no" + i;
paramList.Add(new SqlParameter("@no" + i, trade_no[i]));
}
sql = string.Format(sql, sql1.Substring(" or ".Length)); var ds = SqlHelper.SqlDataSet(ConfigFile.PayCenterConnection, sql, CommandType.Text, paramList.ToArray());
if (ds == null || ds.Tables.Count == )
return null;
return ds.Tables[];
}

【结语】无意中从园子里看到一篇文章,不该活着的SqlHelper和DBHelper,很赞!

-----2016-12-13 09:39:32

【续】方法总比问题多

今天早上刷牙时,灵光一现,对于昨天的方案,不需要通过借助or或union的方式来更改sql的in了,即,可以直接生成如下的sql语句:

select * from T_AlipayNotityRecord where trade_status=@trade_status and trade_no in(@no0,@no1,...)

程序代码在上面的基础上稍做处理:

public DataTable GetAlipayNotifyRecords(AlipayPaymentStatus status, params string[] trade_no)
{
string sql = @"select * from T_AlipayNotityRecord where trade_status=@trade_status and trade_no in({0})"; List<SqlParameter> paramList = new List<SqlParameter>()
{
new SqlParameter("@trade_status",status.ToString()),
};
string sql1 = "";
for (int i = ; i < trade_no.Length; i++)
{
sql1 += ",@no" + i;
paramList.Add(new SqlParameter("@no" + i, trade_no[i]));
}
sql = string.Format(sql, sql1.Substring(",".Length)); var ds = SqlHelper.SqlDataSet(ConfigFile.PayCenterConnection, sql, CommandType.Text, paramList.ToArray());
if (ds == null || ds.Tables.Count == )
return null;
return ds.Tables[];
}

这样子生成的sql就很直观了。比上面方案的还简短。

SqlHelper中IN集合场景下的参数处理的更多相关文章

  1. Android智能手机中各种音频场景下的audio data path

    上一篇文章(Android智能手机上的音频浅析)说本篇将详细讲解Android智能手机中各种音频场景下的音频数据流向,现在我们就开始.智能手机中音频的主要场景有音频播放.音频录制.语音通信等.不同场景 ...

  2. asp.net core中负载均衡场景下http重定向https的问题

    上周欣喜地发现,微软官方终于针对 asp.net core 在使用负载均衡的情况下从 http 强制重定向至 https 的问题提供了解决方法. app.UseForwardedHeaders(new ...

  3. nginx 自动忽略request中header name包含下划线参数的解决方法

    使用nginx过程中遇到了个问题,就是request中的header name中如果包含下划线会自动忽略掉,导致服务器接收不到该字段的内容,以下为解决方法: nginx默认request的header ...

  4. HBase指定大量列集合的场景下并发拉取数据时卡住的问题排查

    最近遇到一例,HBase 指定大量列集合的场景下,并发拉取数据,应用卡住不响应的情形.记录一下. 问题背景 退款导出中,为了获取商品规格编码,需要从 HBase 表 T 里拉取对应的数据. T 对商品 ...

  5. Loadrunner 运行场景-场景中的全局变量与关联结果参数

    运行场景-场景中的全局变量与关联结果参数   by:授客 QQ:1033553122 A.   全局变量 实验1: globals.h #ifndef _GLOBALS_H #define _GLOB ...

  6. Disruptor框架中生产者、消费者的各种复杂依赖场景下的使用总结

    版权声明:原创作品,谢绝转载!否则将追究法律责任. Disruptor是一个优秀的并发框架,可以实现单个或多个生产者生产消息,单个或多个消费者消息,且消费者之间可以存在消费消息的依赖关系.网上其他博客 ...

  7. ASP.NET MVC中默认Model Binder绑定Action参数为List、Dictionary等集合的实例

    在实际的ASP.NET mvc项目开发中,有时会遇到一个参数是一个List.Dictionary等集合类型的情况,默认的情况ASP.NET MVC框架是怎么为我们绑定ASP.NET MVC的Actio ...

  8. Asp.net MVC中提交集合对象,实现Model绑定

    Asp.net MVC中的Model自动绑定功能,方便了我们对于request中的数据的处理, 从客户端的请求数据,自动地以Action方法参数的形式呈现.有时候我们的Action方法中想要接收数组类 ...

  9. Asp.net MVC中提交集合对象,实现Model绑定(转载)

    Asp.net MVC中的Model自动绑定功能,方便了我们对于request中的数据的处理, 从客户端的请求数据,自动地以Action方法参数的形式呈现.有时候我们的Action方法中想要接收数组类 ...

随机推荐

  1. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  2. 【.net 深呼吸】跨应用程序域执行程序集

    应用程序域,你在网上可以查到它的定义,凡是概念性的东西,大伙儿只需要会搜索就行,内容看了就罢,不用去记忆,更不用去背,“名词解释”是大学考试里面最无聊最没水平的题型. 简单地说,应用程序域让你可以在一 ...

  3. [转]Patch文件结构详解

    N久不来 于是不知道扔在哪儿于是放这里先 如果你觉得碍事的话 帮我扔到合适的版块去.. 导读这是一篇说明文 它介绍了标准冒险岛更新文件(*.patch;*.exe)的格式文章的最后附了一段C#的参考代 ...

  4. C# 用SoapUI调试WCF服务接口(WCF中包含用户名密码的验证)

    问题描述: 一般调试wcf程序可以直接建一个单元测试,直接调接口. 但是,这次,我还要测试在接口内的代码中看接收到的用户名密码是否正确,所以,单一的直接调用接口方法行不通, 然后就想办法通过soapU ...

  5. DOM的小练习,两个表格之间数据的移动

    本次讲的是两个表格之间数据的移动,左边的表格移动到右边,并且左边表格移动内容消失. <head>   <meta http-equiv="Content-Type" ...

  6. 原生JS实现-星级评分系统

    今天我又写了个很酷的实例:星级评分系统(可自定义星星个数.显示信息) sufuStar.star();使用默认值5个星星,默认信息 var msg = [........]; sufuStar.sta ...

  7. linux系统oracle-ora12505问题解决方案一

    说明:(1)Linux版本 Linux version 2.6.32.12-0.7-default (geeko@buildhost) (gcc version 4.3.4 [gcc-4_3-bran ...

  8. nginx启动报错:/usr/local/nginx/sbin/nginx: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory

    查看依赖库:

  9. Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录

    一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...

  10. Quality 是什么?

    Quality 是什么? 通常,我们谈及 Quality(质量)时,最常见的问题就是:Quality 是什么? 有很多业界先驱和研究人员已经回答了这个问题,我在这里并不会再给出一个新的答案.在学习总结 ...