SqlHelper.cs是多年前微软出品的一个使用ADO.Net方法对SQL Server数据库进行操作的封装类。而我们自己手写的SqlHelper类同样是对数据库访问方法的一个封装类库,让我们在访问数据库的时候可以很方便地调用其中封装的方法,省略了很多重复劳动。在声明SqlHelper的时候,我们一般会声明为一个静态类,不使用静态类的话有可能产生一些未知的错误(苏老师说微软说的)。

这个类中我们常用的方法如下:

  1. ExecuteNonQuery(): 执行简单的无返回值的查询。
  2. ExecuteReader(): 使用DataReader读取数据。(注:少量数据的情况下使用 SqlDataReader的效率高于使用Dataset)
  3. ExecuteScalar(): 返回结果集中的第一行第一列,相当于返回单个值。
  4. ExcuteDataSet (): 返回Dataset的查询,相当于返回一个数组。

除此之外,我们根据需要以及兴趣也可以再增加一些其他的方法,对其进行修改以及扩展。

第一步、连接字符串
首先需要定义一个只读的连接字符串,连接字符串可以直接写死为一个固定的字符串,也可以从项目的配置文件中取得,一般使用后者:


private static readonly string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
这样的话windows应用程序的配置文件Web.config中可以配置连接字符串如下:
<configuration>
  <connectionStrings>
     <add name="connStr" connectionString="server=.;database=Exam;integrated security=true;"/>
  </connectionStrings>
</configuration>
第二步、封装ExcuteNonQuery

首先先写一个完整的带CommandType参数的方法:

public static int ExcuteNonQuery(string sql, CommandType cmdType, params SqlParameter[] sps){
  using (SqlConnection conn = new SqlConnection(connStr)){
    using (SqlCommand cmd = conn.CreateCommand()){
      if (sps != null){
        cmd.Parameters.AddRange(sps);
       }
      cmd.CommandType = cmdType;
      cmd.CommandText = sql;
      try{
        conn.Open();
        return cmd.ExecuteNonQuery();
      }
      catch (Exception ex){
        conn.Close();
        throw new Exception(ex.Message);
      }
    }
  }
}

在这里,SqlConnection表示Sql Server数据库的一个打开的连接,SqlCommand表示Sql Server数据库执行的一个sql语句或者存储过程。然后再判断参数数组是否为空,不为空时,将参数数组加入到数据库执行命令中。最后打开连接,运行ExecuteNonQuery方法。当然,最好把最后2步try起来,捕获异常并抛出。

有了完整的ExecuteNonQuery方法,我们就可以调用它,通过指定CommandType为CommandType.Text,再封装一个执行Sql语句的重载:

public static int ExcuteNonQuery(string sql, params SqlParameter[] sps){
  return ExcuteNonQuery(sql, CommandType.Text, sps);
}
第三步、封装ExecuteScalar

ExecuteScalar与ExcuteNonQuery的使用一模一样,只是返回值得类型为object而已,这里就不赘述了。


public static SqlDataReader ExceuteReader(string sql, CommandType cmdType, params SqlParameter[] sps){
  SqlConnection conn = new SqlConnection(connStr);
  using (SqlCommand cmd = new SqlCommand(sql, conn)){
    if (sps != null){
      cmd.Parameters.AddRange(sps);
    }
   cmd.CommandType = cmdType;
   try{
     conn.Open();
     return cmd.ExecuteReader(CommandBehavior.CloseConnection);
   }
   catch (Exception ex)   {
   conn.Close();
   throw new Exception(ex.Message);
  }
 }
}

重载方法:

public static SqlDataReader ExcuteReader(string sql, params SqlParameter[] sps){
  return ExceuteReader(sql, CommandType.Text, sps);
}

第四步、ExceuteReader

ExceuteReader方法中返回的是一个SqlDataReader类型的对象reader,使用者拿到这个reader,再通过


while(reader.read())
{
    ……
}
reader.close();
的方式从数据库中一条一条地读取数据,读完之后调用reader的close方法,在这之前,ExceuteReader中的数据库连接不能中断,否则数据库连接中断,用户就无法从数据库中拿到数据了,所以ExceuteReader方法中,数据库连接的创建不能用using包起来,并且执行命令的方法该这样写cmd.ExecuteReader(CommandBehavior.CloseConnection),CommandBehavior.CloseConnection表示在执行该命令时,如果关联的DataReader对象被关闭,那么关联的Connection对象也会被关闭,这样,当调用端调用reader.close()时,数据库连接将被关闭。
public static SqlDataReader ExceuteReader(string sql, CommandType cmdType, params SqlParameter[] sps){
  SqlConnection conn = new SqlConnection(connStr);
  using (SqlCommand cmd = new SqlCommand(sql, conn)){
    if (sps != null){
     cmd.Parameters.AddRange(sps);
    }
    cmd.CommandType = cmdType;
    try{
     conn.Open();
     return cmd.ExecuteReader(CommandBehavior.CloseConnection);
    }
    catch (Exception ex){
     conn.Close();
     throw new Exception(ex.Message);
   }
  }
}
重载方法:
public static SqlDataReader ExcuteReader(string sql, params SqlParameter[] sps){
  return ExceuteReader(sql, CommandType.Text, sps);
}


第五步、ExcuteDataSet

ExcuteDataSet用于返回一个DataSet(也可以返回DataTable, 两者区别不大)。先通过SqlDataAdapter的构造函数声明一个SqlDataAdapter对象da,再调用da的Fill方法,把查询到的表放到DataSet中,最后返回这个DataSet。

public static DataSet ExcuteDataSet(string sql, CommandType cmdType, params SqlParameter[] sps){
  using (SqlConnection conn = new SqlConnection(connStr)){
    using (SqlCommand cmd = new SqlCommand(sql, conn)){
      if (sps != null){
        cmd.Parameters.AddRange(sps);
      }
      cmd.CommandType = cmdType;
      using (SqlDataAdapter da = new SqlDataAdapter(cmd)){
        DataSet ds = new DataSet();
        try{
         conn.Open();
         da.Fill(ds);
         return ds;
        }
        catch (Exception ex){
        conn.Close();
        throw new Exception(ex.Message);
      }
    }
  }
 }
}
上面定义da的这一大串

using (SqlConnection conn = new SqlConnection(connStr)){

using (SqlCommand cmd = new SqlCommand(sql, conn)){
if (sps != null){
cmd.Parameters.AddRange(sps);
}
cmd.CommandType = cmdType;
using (SqlDataAdapter da = new SqlDataAdapter(cmd))

也可以通过SqlDataAdapter的构造方法

public SqlDataAdapter(string selectCommandText, string selectConnectionString) : this()来实现:
SqlDataAdapter da = new SqlDataAdapter(sql, connStr);
da.SelectCommand.CommandType = cmdType;
重载方法:


public static DataSet ExcuteDataSet(string sql, params SqlParameter[] sps){
  return ExcuteDataSet(sql, CommandType.Text, sps);
}