微软SqlHelper详细解读
发现很少有人使用微软SqlHelper,大多数人都是自己实现或把微软的进行阉割。其原因大概有以下几个:
1、有些人认为微软的SqlHelper很多东西没有必要,担心影响性能。
2、微软的SqlHelper有60多个方法,加上缓存类有70多个。由于类的方法的低耦合使得源码阅读困难。
3、自己实现也不难,因为是自己写的,使用时思路更清晰,而且改动更灵活。
那是因为很多人看到这么多方法给吓着了,根本没有把源码从头到尾认真看一遍。就算看也是看几个方法就看晕了,一大堆方法重载,各方法之间相互引用。
很不幸,本人就是看了几次到中途就绕晕了的人。每当被绕晕的时候就总觉得,太没必要了,微软把简单的东西给搞得这么复杂,自己写的简单完全能满足要求,就放弃了。
可前两天发生一件事,让我觉得是应该好好看看微软的原版了,于时就有了下面这些笔记。
一、SqlHelper是密封类,并且不能实例化。
注意:微软的SqlHelper类中并没有读写配置文件的代码,像这样“public static string ConnectionString = ConfigurationManager.ConnectionStrings["connstring"].ConnectionString;”。甚至,在类库要通过添加.net组件System.Configuration才能使用ConnectionManager类,其原因就是它使SqlHelper的可移植性变差。你想想,如果没有这行代码,我把SqlHelper编译成DLL文件,那么这个DLL在别的项目添加组件引用就可以使用了。如果有了这行代码,编译成DLL文件,在别的项目除了添加引用外,还要在配置文件添加一个连接字符串,这个连接字符的名字是什么呢?一般这个连接字符串的名称通过文档或口述方式获取,如果在传输过程中丢失了,那这个DLL还怎么用。
二、对方法进行分类
这样分一下类,应该清晰多了吧?(图中用红线圈的2区5个方法是对红线1区5个方法的补充,一一对应。后面详细讲解它们之间的关系。)
从图中我们看到,SqlHelper是由两上类组成的,一个是真正的SqlHelper内,另一个是辅助类,为查询操作提供缓存。
为了简便,我们先抛开缓存类,那么SqlHelper类可以分为两部分,私有方法和公开方法。
注意:用蓝线圈出来的是OleDb下没有ExecuteXmlReader方法,即:你要把这个类改成OleDb的去掉蓝线圈的几个方法。
三、各个击破之私有方法
SqlHelper类中私有方法只有5个,有1个私有的枚举。不多!
但是我们从下面这张图可以看出它们的重要性
其中图中最左边两个是“AssignParameterValues”方法(2重载),作用是为参数列表赋值。
从右到左第二列的那个是“PrepareCommand ”方法,从图中可看到它的地位可不一般,几乎所有的类到最后都要调用它。其实它是职责是为执行命令作准备工作,比如最常见的打开数据库连接就在其中完成。它旁边那个是它的小弟,作用是为命令添加参数。
最上面那一个是“ExecuteReader ”,是数据阅读器都最终都是调用了它。它和其他4个有些区别,注意区分。
四、各个击破之公共方法
这个太多,我们以以其中一个为准,详细说明,其余的以此类推。
前面第二节我们说:“图中用红线圈的2区5个方法是对红线1区5个方法的补充,一一对应”,
我们这以第一个方法为例(上图中行号176——417的9个重载+行号1782——1867的三个方法),看看微软是怎么重载的。
文字一大堆,不如来个表格直观,各方法要求参数如下:
方法名称 | 连接类型 | 执行T-SQL语句 | 存储过程 | 参数(带*号的为可null) | |
1 | ExecuteNonQuery | 字符串 | Yes | Yes | No |
2 | ExecuteNonQuery | 字符串 | Yes | Yes | Yes* |
3 | ExecuteNonQuery | 字符串 | No | Yes | Yes* |
4 | ExecuteNonQuery | 连接对象 | Yes | Yes | No |
5 | ExecuteNonQuery | 连接对象 | Yes | Yes | Yes* |
6 | ExecuteNonQuery | 连接对象 | No | Yes | Yes* |
7 | ExecuteNonQuery | 事务 | Yes | Yes | No |
8 | ExecuteNonQuery | 事务 | Yes | Yes | Yes* |
9 | ExecuteNonQuery | 事务 | No | Yes | Yes* |
10 | ExecuteNonQueryTypedParams | 字符串 | No | Yes | Yes |
11 | ExecuteNonQueryTypedParams | 连接对象 | No | Yes | Yes |
12 | ExecuteNonQueryTypedParams | 事务 | No | Yes | Yes |
看到没有,方法虽多,但没有重复的吧。你可能会说,怎么没重复的,第一个和第二个就重复了,调用第二个方法如果没参数传个null不就和第一个方法重复了么?
其实,重载了这么多就是为了消除可null参数,也就是说,在外部调用SqlHelper中方法时永远不要为参数传递null值,如果不是为了这点,上面的12个方法完全可以压缩成2个。
不信,我们就来试试看,是不是能压缩成2个方法。先看张图片
这张图是总图的部分放大,由图我们可以清楚的看到12个方法的引用关系,可以看到1、2、3、4、6、10、11最终都调用了5,12、7、9最终都调用了8.
也就是说,如果可以参数可以传null的话,我们只需要5和8两个方法就行了(一个执行普通连接,一个执行事务)。
由此可以推出,如果是全图的话,就只要右边三列的方法就可以了,其余左边三列都是对右边三列的包装。
为什么不能使用可空参数?和前面提到的不推荐读配置文件是一个道理,为了可移植性。因为在SqlHelper发布成DLL后,调用时如何知道那些参数可接受null值那些参数不可接受null值呢!
到此为止吧,剩下的按也就是按这个思路来就行了,
最后补充一点,读源码的时候在重载方法的XML注释进行编号,容易阅读。不然光靠参数来分辨容易搞晕。
像这样,结合上面的表格,就清楚的知道了第一个方法引用的是第二个方法。