如果你经常从事基于.NET的应用程序的数据库开发,你会有这种感觉--总是觉得自己在反复编写相同的数据访问代码。很多相似的代码每天在复制来,粘贴去。你是否想过将数据访问代码包装在一个Helper函数里,以便能够在不同的类中共用?如果你还没有这样做,那么我这里就告诉你如何从复用的角度来设计和包装一个我们自己的数据访问类,从而减少冗余代码,提高开发效率。
重点:
Ø 执行命令方法的封装
Ø 查询数据方法的封装
Ø 统计数据方法的封装
Ø SqlParameter的封装
预习功课:
Ø 执行命令方法的封装
Ø 查询数据方法的封装
Ø 统计数据方法的封装
Ø SqlParameter的封装
6.1. 执行命令方法的封装
当我们执行增加、更新、删除命令的时候,一般会这样来写:
1. string conString = "data source=127.0.0.1;database=codematic;user id=sa; 2. password="; 3. SqlConnection myConnection = new SqlConnection(conString ); 4. string strSql = "update P_Product set Name='电脑3' where Id=52"; 5. SqlCommand myCommand = new SqlCommand(strSql, myConnection); 6. myConnection.Open(); 7. int rows = myCommand.ExecuteNonQuery(); 8. myConnection.Close();
如果是很多个这样的操作,那么我们就需要写很多基本相似的代码。根据面对对象的抽象原则,在这些操作里面有很多共性的东西,唯一的不同就是conString和strSql。那我是不是可以将共性的东西抽象出来将其封装为所有操作所共用呢?
我们把共性的东西抽象出一个独立方法:
1. //<summary> 2. //执行SQL语句,返回影响的记录数 3. //</summary> 4. public int ExecuteSql(string StrSql, string conString) 5. { 6. using (SqlConnection connection = new SqlConnection(conString)) 7. { 8. using (SqlCommand cmd = new SqlCommand(StrSql, connection)) 9. { 10. connection.Open(); 11. int rows = cmd.ExecuteNonQuery(); 12. return rows; 13. } 14. } 15. }
这样,实际调用的代码就可以变成:
1. string conString="data source=127.0.0.1;database=codematic;user id=sa; 2. password="; 3. string strSql = "update P_Product set Name='电脑3' where Id=52"; 4. int rows =ExecuteSql(strSql, conString);
是不是简单了很多?可以让其他类共用这个方法,重复代码少了,工作效率提高了。
如果所连数据库都是固定不变的,也就是说连接字符串一般不变,那么我们可以将conString提取出来放到一个变量里面,所有的方法都用这个变量。想改变数据库时,直接修改变量的内容即可,在实际调用的时候不需要传连接字符串,是不是又省了一步?为了更好地复用,我们还可以将该方法放到单独的类DbHelperSQL里面去。
DbHelperSQL类中:
1. public class DbHelperSQL 2. { 3. public static string conString = "data source=127.0.0.1; 4. database=codematic;user id=sa;password="; 5. //<summary> 6. //执行SQL语句,返回影响的记录数 7. //</summary> 8. //<param name="StrSql">SQL语句</param> 9. //<returns>影响的记录数</returns> 10. public static int ExecuteSql(string StrSql) 11. { 12. using (SqlConnection connection = new SqlConnection(conString)) 13. { 14. using (SqlCommand cmd = new SqlCommand(StrSql, connection)) 15. { 16. connection.Open(); 17. int rows = cmd.ExecuteNonQuery(); 18. return rows; 19. } 20. } 21. } 22. }
了使用方便和节省资源,我们将变量和方法设计成静态的。此时的调用就变成了:
1. string strSql = "update P_Product set Name='电脑3' where Id=52";
2. int rows = DbHelperSQL.ExecuteSql(strSql);
为了以后的维护和扩展,数据库连接字符串最好放在Web.config里面,这样以后想改数据库就直接改一下Web.config即可,而无须重新编译代码。
1. Web.config加入: 2. <appSettings> 3. <add key="ConnectionString" value="server=127.0.0.1; database=codematic; 4. uid=sa;pwd="/> 5. </appSettings> 6. 变量获取该字符串: 7. public static string conString = ConfigurationManager.AppSettings 8. ["ConnectionString "];
有时候为了安全,我们可能会对Web.config中的连接字符串进行加密。这样就需要在获取连接字符串的时候进行解密。这样,单凭上面一句代码可能就无法解决了,我们还需要单独的处理方法来处理。为了更好地降低耦合性,减少对类的依赖,我们可以将获取数据库连接字符串的操作单独放到一个类里面,如PubConstant。这样以后修改相应的连接规则和加密处理时,直接调用各个模块的这个类就可以了,而并不需要知道实际的各个模块的数据库访问类是怎么获取的。
例如Web.config的<appSettings>设置:
1. <add key="ConStringEncrypt" value="false"/> 2. <add key="ConnectionString" value="server=127.0.0.1;database=codematic; 3. uid=sa;pwd="/> 4. 公共常量类获取并处理: 5. public class PubConstant 6. { 7. //<summary> 8. //获取连接字符串,判断是否加密处理 9. //</summary> 10. public static string ConString 11. { 12. get 13. { 14. string _conString = ConfigurationManager.AppSettings ["ConString"]; 15. string ConStringEncrypt = ConfigurationManager.AppSettings 16. ["ConStringEncrypt"]; 17. if (ConStringEncrypt == "true")//是加密的 18. { 19. _conString = DESEncrypt.Decrypt(_conString);//解密 20. } 21. return _conString; 22. } 23. } 24. } 25. 使用连接字符串: 26. public static string conString = PubConstant.ConString;
最后的各个类的调用关系如下图所示:
6.2 查询数据方法的封装
和上面同样的道理。我们采用同样的思想对查询方法进行封装处理。
查询数据的源代码:
1. string conString = "data source=127.0.0.1;database=codematic;user id=sa; 2. password="; 3. string strSQL = "SELECT * FROM P_Product"; 4. SqlConnection myConnection = new SqlConnection(conString); 5. DataSet ds = new DataSet(); 6. myConnection.Open(); 7. SqlDataAdapter adapter = new SqlDataAdapter(strSQL, myConnection); 8. adapter.Fill(ds, "ds"); 9. myConnection.Close(); 10. 封装后: 11. //<summary> 12. //执行查询语句,返回DataSet 13. //</summary> 14. //<param name="StrSql">查询语句</param> 15. //<returns>DataSet</returns> 16. public static DataSet Query(string StrSql) 17. { 18. using (SqlConnection connection = new SqlConnection(conString)) 19. { 20. DataSet ds = new DataSet(); 21. connection.Open(); 22. SqlDataAdapter command = new SqlDataAdapter(StrSql, connection); 23. command.Fill(ds, "ds"); 24. return ds; 25. } 26. } 27. 调用代码: 28. string strSql = "SELECT * FROM P_Product"; 29. DataSet ds = DbHelperSQL.Query(strSql);
6.3 数据统计方法的封装
数据统计方法的源代码:
1. string conString = "data source=127.0.0.1;database=codematic;user id=sa; 2. password="; 3. SqlConnection myConnection = new SqlConnection(conString); 4. string strSql = "select count(*) from P_Product"; 5. SqlCommand myCommand = new SqlCommand(strSql, myConnection); 6. myConnection.Open(); 7. int count = (int)myCommand.ExecuteScalar(); 8. myConnection.Close(); 封装后的方法: 1. //<summary> 2. //执行一条计算查询结果语句,返回查询结果(object) 3. //</summary> 4. //<param name="StrSql">计算查询结果语句</param> 5. //<returns>查询结果(object)</returns> 6. public static object GetSingle(string StrSql) 7. { 8. using (SqlConnection connection = new SqlConnection(conString)) 9. { 10. using (SqlCommand cmd = new SqlCommand(StrSql, connection)) 11. { 12. connection.Open(); 13. object obj = cmd.ExecuteScalar(); 14. if((Object.Equals(obj,null))||(Object.Equals(obj,System.DBNull.Value))) 15. { 16. return null; 17. } 18. else 19. { 20. return obj; 21. } 22. } 23. } 24. } 25. 26. 调用代码: 27. string strSql = " select count(*) from P_Product "; 28. string num = DbHelperSQL.GetSingle(strSql).ToString();
6.4 实现SqlParameter方式
因为通过SQL语句的方式,有时候存在脚本注入的危险,所以在大多数情况下不建议用拼接SQL语句字符串方式,希望通过SqlParameter实现来实现对数据的操作,针对SqlParameter的方式我们同样可以将其封装成一个可以复用的数据访问类,只是比SQL语句的方式多了一个SqlParameter的参数。
具体代码如下:
1. //<summary> 2. //执行SQL语句,返回影响的记录数 3. //</summary> 4. //<returns>影响的记录数</returns> 5. public static int ExecuteSql(string StrSql, params SqlParameter[] cmdParms) 6. { 7. using (SqlConnection connection = new SqlConnection(conString)) 8. { 9. using (SqlCommand cmd = new SqlCommand()) 10. { 11. PrepareCommand(cmd, connection, null, StrSql, cmdParms); 12. int rows = cmd.ExecuteNonQuery(); 13. cmd.Parameters.Clear(); 14. return rows; 15. } 16. } 17. } 18. //<summary> 19. //执行查询语句,返回DataSet 20. //</summary> 21. //<returns>DataSet</returns> 22. public static DataSet Query(string StrSql, params SqlParameter[] cmdParms) 23. { 24. using (SqlConnection connection = new SqlConnection(conString)) 25. { 26. SqlCommand cmd = new SqlCommand(); 27. PrepareCommand(cmd, connection, null, StrSql, cmdParms); 28. using (SqlDataAdapter da = new SqlDataAdapter(cmd)) 29. { 30. DataSet ds = new DataSet(); 31. da.Fill(ds, "ds"); 32. cmd.Parameters.Clear(); 33. return ds; 34. } 35. } 36. }