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.  }

时间: 2024-10-24 13:26:43

C#二十九 数据封装的相关文章

攻城狮在路上(叁)Linux(二十九)--- 完整备份工具:dump以及restore

一.dump命令: 该命令既可以针对整个文件系统进行备份,也可以仅针对目录来备份.还可以指定不同的备份等级(-0~-9共10个等级). dump -W:列出在/etc/fstab中具有dump设置的分区是否备份过. 命令格式: dump [-Suvj] [-level] [-f 备份文件] 待备份数据 参数说明: -S:仅列出后面的待备份数据所需要的磁盘空间大小. -u:将这次dump的时间记录到/etc/dumpdates文件中. -v:将dump的文件过程显示出来. -j:加入bzip2的支

企业搜索引擎开发之连接器connector(二十九)

在哪里调用监控器管理对象snapshotRepositoryMonitorManager的start方法及stop方法,然后又在哪里调用CheckpointAndChangeQueue对象的resume方法获取List<CheckpointAndChange> guaranteedChanges集合 下面跟踪到DiffingConnectorTraversalManager类的相关方法,在该类实现的方法中,调用了监控器管理对象snapshotRepositoryMonitorManager的相

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout.RecyclerView和CardView 前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框.DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框.这一节我们介绍几个新的API控件SwipeRefreshLayout.RecyclerView和CardView,这几个API控件都是google在Android5.0推出的.下面我们来学

[原创]ActionScript3游戏中的图像编程(连载二十九)

2.2.2 Photoshop投影大小的模拟 投影没有之前那么浓了,但是跟Photoshop里的效果差别还挺大,因为在Photoshop里我们还设置了另外一个属性:大小. Flash里似乎找不到它的影子,我们用排除法来进行定位,Photoshop投影样式的大小属性以像素为单位,Flash投影滤镜的选项只有距离和那对被“手铐”扣住的模糊属性符合条件,而Photoshop里也有一个距离,所以我们定位到模糊属性(图 2.15). 图 2.15 Flash投影的模糊属性 分别调整Photoshop的大小

Welcome to Swift (苹果官方Swift文档初译与注解二十九)---209~218页(第四章-- 流程控制)

Break break语句会立刻结束整个流程控制的执行.break语句可以在switch语句或者循环语句中帮助你提前结束循环或者switch的执行. Break in a Loop Statement  (循环语句中的break) 当在循环语句中使用break,会立刻结束循环的执行,并且跳转到循环体之后的第一行代码.循环不会再遍历执行了. Break in a Switch Statement (switch语句的break) 当在switch语句中使用break,break会立刻结速switc

每日算法之二十九:Search in Rotated Sorted Array

在一个经过旋转后的有序数组中查找一个目标元素. Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). You are given a target value to search. If found in the array return its index, otherwise return -1.

ActionScript3游戏中的图像编程(连载二十九)

2.2.2 Photoshop投影大小的模拟 投影没有之前那么浓了,但是跟Photoshop里的效果差别还挺大,因为在Photoshop里我们还设置了另外一个属性:大小. Flash里似乎找不到它的影子,我们用排除法来进行定位,Photoshop投影样式的大小属性以像素为单位,Flash投影滤镜的选项只有距离和那对被"手铐"扣住的模糊属性符合条件,而Photoshop里也有一个距离,所以我们定位到模糊属性(图 2.15). 图 2.15 Flash投影的模糊属性 分别调整Photosh

【Unity 3D】学习笔记二十九:游戏实例——简单小地图制作

任何的学习,光看不练是学不好的.所以这次就总结回顾下怎么制作MMROPG类游戏中的小地图.在MMROPG类游戏里,主角在游戏世界里走动时,一般在屏幕右上角都会有一个区域来显示当前游戏场景的小地图.主角在游戏世界里走动,小地图里代表着主角的小标记也会随之移动.那怎么实现咧? 首先需要确定两个贴图,第一个是右上角的小地图背景贴图,应该是从Y轴俯视向下截取主角所在的位置大地图.第二个就是主角的位置大贴图.在本例中,因为没有学习unity地图制作,所以地图用一个面对象代替,主角用立方体代替,使用GUI来

二十九、linux常用命令(一)

vim是打开vim编辑器,别的编辑器还有vi(功能没有vim 强大),nano,emacs等等,感觉还是vim最强大,其次是vi,别的就要差一些了. 我听我们老师说,用图形界面本身已经会被高手笑了,如果打开一个gpedit或者kwrite那就废了......常用的命令 ls,列出当前目录下的文件,ls -l是列出详细信息,ls -a列出隐藏文件. cd,更改目录.clear,清屏命令.reset,重置终端. startx,启动图形界面.fdisk -l,查看硬盘分区. ps aux,列出系统进程