C#二十九 数据封装

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: C#二十九 数据封装

 如果你经常从事基于.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.  } 
目录
相关文章
|
8月前
|
C# 数据库
c# dev Form1 gridview1使用Form2 gridview1的数据
c# dev Form1 gridview1使用Form2 gridview1的数据
|
8天前
|
开发框架 .NET Java
C#集合数据去重的5种方式及其性能对比测试分析
C#集合数据去重的5种方式及其性能对比测试分析
27 11
|
10天前
|
开发框架 .NET Java
C#集合数据去重的5种方式及其性能对比测试分析
C#集合数据去重的5种方式及其性能对比测试分析
40 10
|
5月前
|
测试技术 API C#
C#使用Bogus生成测试数据
C#使用Bogus生成测试数据
62 1
|
3月前
|
SQL 缓存 分布式计算
C#如何处理上亿级数据的查询效率
C#如何处理上亿级数据的查询效率
52 1
|
4月前
|
安全 C#
C# 面向对象编程的三大支柱:封装、继承与多态
【9月更文挑战第17天】在C#中,面向对象编程的三大支柱——封装、继承与多态,对于编写安全、可维护、可复用的代码至关重要。封装通过访问修饰符和属性保护数据;继承允许子类继承父类的属性和方法,实现代码复用和多态;多态则提高了代码的灵活性和通用性。掌握这三大概念能显著提升C#编程能力,优化开发效率和代码质量。
|
4月前
|
存储 C# 开发者
枚举与结构体的应用:C#中的数据组织艺术
在C#编程中,枚举(`enum`)和结构体(`struct`)是非常重要的数据类型。枚举用于定义命名常量集合,提高代码可读性;结构体则封装相关数据字段,适合小型数据集。本文从基本概念入手,探讨它们的使用技巧、常见问题及解决方案,帮助开发者更好地利用这些特性构建健壮的应用程序。
58 8
|
3月前
|
中间件 数据库连接 API
C#数据分表核心代码
C#数据分表核心代码
49 0
|
3月前
|
XML JSON 前端开发
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
679 0
|
5月前
|
存储 C# 数据库
解决C#对Firebase数据序列化失败的难题
在游戏开发中,Unity结合Firebase实时数据库为开发者提供强大支持,但在C#中进行数据序列化和反序列化时常遇难题。文章剖析了数据丢失或反序列化失败的原因,并给出解决方案,包括使用`JsonUtility`、确保字段标记为`[Serializable]`以及正确配置网络请求。示例代码演示了如何在Unity环境中实现Firebase数据的序列化和反序列化,并通过设置代理IP、Cookies和User-Agent来增强网络请求的安全性。这些技巧有助于确保数据完整传输,提升开发效率。
解决C#对Firebase数据序列化失败的难题