ASP.NET系统开发(一):层层递进之SQLHelper助手类的持续优化
ASP.NET开发中的三层开发思想指的是UI层(界面显示层),BLL层(业务逻辑层),DAL层(数据访问层)三层,三层之间通过函数的调用来达到降低耦合,易于系统维护的目的,SQLHelper助手类的主要作用在于接收并执行来自各个数据表累传来的sql语句或存储过程。一般的SQLHelper类中主要包括以下几个函数功能:
1.执行不带参数的增删改方法
2.执行带参数的增删改方法。
3.执行不带参数的查询方法。
4.执行带参数的查询方法。
作为一个程序员SQLHelper类编写的好坏不仅影响着系统的可维护性的强弱,而且它更体现的是一个编程人员的职业素质。一个程序员的成长过程中必然要经过代码的锤炼,代码见证了一个编程人员的成长历程,下面通过不同版本的SQLHelper类来向大家展示一个良好的SQLHelper助手类是怎样炼成的:
一、初涉江湖版(A级代码)
namespace dal{ public class SQLHelper { /// 执行带参数的增删改方法 public int ExecuteNonQuery(string sqltext,CommandType ct,SqlParameter [] paras) { string strconn ="server=YCH-PC;database=newssystem;uid=sa;pwd=1314517"; SqlConnection conn = new SqlConnection(strconn); //定义一个数据库连接对象(下同) conn.Open(); //打开数据库连接(下同) SqlCommand cmd = new SqlCommand(sqltext , conn ); //实例化一个命令对象(下同) cmd.CommandType = ct; //指定命令类型(下同) cmd.Parameters.AddRange(paras); //增加参数(下同) int res = cmd.ExecuteNonQuery(); //执行命令(下同) conn .Close (); //关闭数据库连接(下同) return res; //返回执行结果(下同) } /// 执行不带参数的增删改方法 public int ExecuteNonQuery(string sqltext, CommandType ct) { string strconn = "server=YCH-PC;database=newssystem;uid=sa;pwd=123456"; SqlConnection conn = new SqlConnection(strconn); conn.Open(); SqlCommand cmd = new SqlCommand(sqltext, conn); cmd.CommandType = ct; int res = cmd.ExecuteNonQuery(); conn.Close(); return res; } /// 执行不带参数的查询方法 public DataTable ExecuteQuery(string sqltext, CommandType ct) { string strconn = "server=YCH-PC;database=newssystem;uid=sa;pwd=123456"; SqlConnection conn = new SqlConnection(strconn); conn.Open(); SqlDataReader sdr ; DataTable dt=new DataTable (); SqlCommand cmd = new SqlCommand(sqltext, conn); cmd.CommandType = ct; sdr = cmd.ExecuteReader(); dt.Load(sdr); conn.Close(); return dt ; } /// 执行带参数的查询操作 public DataTable ExecuteQuery(string sqltext, CommandType ct, SqlParameter[] paras) { string strconn = "server=YCH-PC;database=newssystem;uid=sa;pwd=123456"; SqlConnection conn = new SqlConnection(strconn); conn.Open(); SqlDataReader sdr; DataTable dt = new DataTable(); SqlCommand cmd = new SqlCommand(sqltext, conn); cmd.CommandType = ct; cmd.Parameters.AddRange(paras); sdr = cmd.ExecuteReader(); dt.Load(sdr); conn.Close(); return dt ; } }}
二、血雨腥风版(AA级代码)
从上面的代码中我们可以很明显的看出,各个函数中数据库连接字符串、连接对象以及数据库连接的打开和关闭都是相同的,代码的重复往往是糟糕代码的标志,下面我们就通过代码改造来减少代码冗余,提高代码的复用率。代码的主要改动部分就是针对上述相同的代码片段进行的:
namespace dal{ public class SQLHelper { private SqlConnection conn = null; private SqlCommand cmd = null; /// 实例化SQLHelper类的时候便实例化一个数据库连接 public SQLHelper() { string connStr = "server=YCH-PC;database=newssystem;uid=sa;pwd=123456"; conn = new SqlConnection(connStr); } /// 打开数据库连接 private SqlConnection GetConn() { if (conn.State == ConnectionState.Closed) { conn.Open(); } return conn; } /// 关闭数据库连接 private void OutConn() { if (conn.State == ConnectionState.Open) { conn.Close(); } } /// 执行不带参数的增删改操作 public int ExecuteNonQuery(string cmdText, CommandType ct) { cmd = new SqlCommand(cmdText, GetConn()); cmd.CommandType = ct; int res = cmd.ExecuteNonQuery(); OutConn(); return res; } /// 执行带参数的增删改方法 public int ExecuteNonQuery(string sqltext, CommandType ct, SqlParameter[] paras) { SqlCommand cmd = new SqlCommand(sqltext, GetConn()); cmd.CommandType = ct; cmd.Parameters.AddRange(paras); int res = cmd.ExecuteNonQuery(); OutConn(); return res; } /// 执行不带参数的查询方法 public DataTable ExecuteQuery(string sqltext, CommandType ct) { DataTable dt = new DataTable(); SqlCommand cmd = new SqlCommand(sqltext, GetConn()); cmd.CommandType = ct; SqlDataReader sdr = cmd.ExecuteReader(); dt.Load(sdr); sdr.Close(); OutConn(); return dt; } /// 执行带参数的查询操作 public DataTable ExecuteQuery(string sqltext, CommandType ct, SqlParameter[] paras) { DataTable dt = new DataTable(); SqlCommand cmd = new SqlCommand(sqltext, GetConn()); cmd.CommandType = ct; cmd.Parameters.AddRange(paras); SqlDataReader sdr = cmd.ExecuteReader(); dt.Load(sdr); sdr.Close(); OutConn(); return dt ; } }}
三、炉火纯青版(AAA级代码)
通过”瘦身行动“,现在的代码是不是比第一版代码清晰了很多呢?但这还不是最后的结果。有的人会提出这样的问题:把连接字符串写在SQLHelper类中,如果我现在要更换数据库,那岂不是要对SQLHelper助手类进行更改,这样似乎不符合我们”开放扩展,关闭修改“的要求。另外在执行查询过程时需要先关闭SqlDataReader再关闭数据库连接,这样在代码中也出现了重复,能不能再进一步对代码进行改造来解决这两个问题呢?下面我们就上述两个问题对代码进行进一的步改造: 解决更换数据库的问题我们采取的方法是将连接字符串写在配置文件中,具体步骤为:
1. 双击web层中Web.config文件,配置文件中的相关内容将会出现。
2. 找到<connectionStrings>和</connectionStrings>,在二者之间添加如下内容:<add name=<add name=连接字符串 connectionString ="server=YCH-PC;database=newssystem;uid=sa;pwd=具体的登陆密码"/>
3. 修改SQLHelper类中的相关代码如下:
namespace dal{ public class SQLHelper { private SqlConnection conn = null; private SqlCommand cmd = null; private SqlDataReader sdr = null; public SQLHelper() { string strconn = ConfigurationManager.ConnectionStrings["strconn"].ConnectionString; conn = new SqlConnection(strconn ); } private SqlConnection GetConn() { if (conn.State == ConnectionState.Closed) { conn.Open(); } return conn; } //关闭数据库连接 private void OutConn() { if (conn.State == ConnectionState.Open) { conn.Close(); } } /// 执行不带参数的增删改SQL语句或存储过程 public int ExecuteNonQuery(string cmdText, CommandType ct) { int res; try { cmd = new SqlCommand(cmdText, GetConn()); cmd.CommandType = ct; res = cmd.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { OutConn(); } return res; } /// 执行带参数的增删改SQL语句或存储过程 public int ExecuteNonQuery(string cmdText, SqlParameter[] paras, CommandType ct) { int res; try { cmd = new SqlCommand(cmdText, GetConn()); cmd.CommandType = ct; cmd.Parameters.AddRange(paras); res = cmd.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { OutConn(); } return res; } /// 执行不带参数的查询SQL语句或存储过程 public DataTable ExecuteQuery(string cmdText, CommandType ct) { DataTable dt = new DataTable(); cmd = new SqlCommand(cmdText, GetConn()); cmd.CommandType = ct; using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { dt.Load(sdr); } return dt; } /// 执行带参数的查询SQL语句或存储过程 public DataTable ExecuteQuery(string cmdText, SqlParameter[] paras, CommandType ct) { DataTable dt = new DataTable(); cmd = new SqlCommand(cmdText, GetConn()); cmd.CommandType = ct; cmd.Parameters.AddRange(paras); using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { dt.Load(sdr); } return dt; } }}
经过对代码的再次改造,不但代码的重复率大大降低,而且如需更换数据库,只要在配置文件中更改相应的连接字符串就可完。在编写查询(包括带参数的和不带参数的查询方法)方法时,用using方法,在关闭SqlDataReader对象的时候同时关闭与之相关联的数据库连接,避免了try catch语句的使用,代码更加简洁。经过三次改造,SQLHelper助手类的变身就此完成。