我手头有个古老的项目,持久层用的是古老的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. npm 私有模块的管理使用

    你可以使用 NPM 命令行工具来管理你在 NPM 仓库的私有模块代码,这使得在项目中使用公共模块变的更加方便. 开始前的工作 你需要一个 2.7.0 以上版本的 npm ,并且需要有一个可以登陆 np ...

  2. Electron使用与学习--(基本使用与菜单操作)

    对于electron是个新手,下面纯属个人理解.如有错误,欢迎指出.   一.安装 如果你本地按照github上的 # Install the `electron` command globally ...

  3. 【NLP】Python NLTK获取文本语料和词汇资源

    Python NLTK 获取文本语料和词汇资源 作者:白宁超 2016年11月7日13:15:24 摘要:NLTK是由宾夕法尼亚大学计算机和信息科学使用python语言实现的一种自然语言工具包,其收集 ...

  4. MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决

    一.简介 MySQL是最流行的开放源码SQL数据库管理系统,它是由MySQL AB公司开发.发布并支持的.有以下特点: MySQL是一种数据库管理系统. MySQL是一种关联数据库管理系统. MySQ ...

  5. Take into Action!

    很久没有认真地写文字了. 刚毕业一两年断断续续在csdn上写过一些当时的工作记录,然后没有坚持下去.有时候是觉得自己不牛,记录的东西旁人看起来也许不值一提:有时候觉得结婚生娃了,然后时间不够用(确实是 ...

  6. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  7. 易用BPM时代,企业如何轻松驾驭H3?

    众所周知,BPM作为企业发展的推动力,能敏捷高效的融合业务流程和信息资源.通过综合考虑流程的成本.效率.质量等方面因素,用IT系统将调整后的流程固化下来,从而降低企业管理成本,提高内部运营效率,提升企 ...

  8. Quartz2D总结

    天了噜,脑子完全懵了,最起码说出来个上下文啊,连这个都给忘了,特此总结一下,并以此缅怀这次面试 Quartz2D的API来自于Core Graphics(这就是为什么CGContextRef是以CG开 ...

  9. Android种使用Notification实现通知管理以及自定义通知栏(Notification示例四)

    示例一:实现通知栏管理 当针对相同类型的事件多次发出通知,作为开发者,应该避免使用全新的通知,这时就应该考虑更新之前通知栏的一些值来达到提醒用户的目的.例如我们手机的短信系统,当不断有新消息传来时,我 ...

  10. 安装并使用PHPunit

    安装并使用PHPunit Linux 下安装PHPunit PHP 档案包 (PHAR)  要获取 PHPUnit,最简单的方法是下载 PHPUnit 的 PHP 档案包 (PHAR),它将 PHPU ...