使用存储过程会给程序设计上带来很多的方便,也可使程序开发师的分工更加明确,最主要的是可以提高系统性能。前些日子在下在开发过程中遇到一些问题,现在写下来分享分享经验,希望能给你们节约些时间。

  1,返回值和输出参数的区别。

   -- 在新增用户的同时,获得主键;输出参数的形式。

  create procedure AddUser(

    @UserName nvarchar(12),

    @Password nvarchar(12),

    @UserId int output

  )as

    begin

      select @UserId=max(UserId) + 1 from Users

      insert into Users(UserName,Password) values(@UserName,@Password)

    end

   --返回值形式

  create procedure AddUser(

    @UserName nvarchar(12),

    @Password nvarchar(12)

  )  

    as

      begin

        declare @UserId int

        select @UserId=max(UserId) + 1 from Users

        insert into Users(UserName,Password) values(@UserName,@Password)

        return @UserId

      end

  C#调用代码

    string procName = “AddUser”;

    using(SqlCommand comm= new SqlCommand(procName,conn))

    {

      comm.CommandType = CommadnType.StoredProcedure;

      comm.Parameters.Add(new SqlParameter("@UserName",SqlDbType.NVarChar,12));

      comm.Parameters.Add(new SqlParameter("@Password",SqlDbType.NVarChar,12));

      comm.Parameters.Add(new SqlParameter("@UserId",SqlDbType.Int));

      comm.Parameters["@UserName"].Value = user.UserName;

      comm.Parameters["@Password"].Value = user.Password;

      comm.Parameters["@UserId"].Direction = ParameterDirection.Output;

      comm.ExecuteNonQuery();

      int userId = (int)comm.Parameters["@UserId"].Value;

      comm.Conection.Close();

    }

  这样就能获得AddUser的输出参数的值了;如何获得返回值呢?很简单:

    comm.Parameters["@UserId"].Direction = ParameterDirection.ReturnValue;

  也可以同时接收输出参数和返回值,但是两者之间是有差别的:

  a,在存储过程中只能返回一个值,且必须是整型的;输出参数可以为任何类型,可以有多个。

  b,在存储过程执行到return语句,后面的语句将不会执行,终止执行并返回结果;为输出参数赋值后,存储过程会继续执行至结束或return语句。

  2,ExecuteReader()方法。

   create procedure SelAllUser(

    @Count int output

  )

    as

      begin

        select @Count=count(*) from Users

        select * from Users

      end

  如果需要获取存储过程中查询语句的结果集,可以使用SqlCommand的ExecuteReader()方法:

    string procName = “AddUser”;

    using(SqlCommand comm= new SqlCommand(procName,conn))

    {

      comm.CommandType = CommadnType.StoredProcedure;

      comm.Parameters.Add(new SqlParameter("@Count ",SqlDbType.Int));

      comm.Parameters["@Count "].Direction = ParameterDirection.Output;

      SqlDataReader sdr = comm.ExecuteReader();

      while(sdr.Reader())

      {

        ……

      }

      sdr.Close();

      int count = (int)comm.Parameters["@UserId"].Value;

      comm.Conection.Close();

    }

  查询结果得到了,你会发现count的值会一直是0,原因在于ExecuteReader()方法并不会接收存储过程的

 输出参数和返回值。可以这样解决:

    string procName = “AddUser”;

    using(SqlCommand comm= new SqlCommand(procName,conn))

    {

      comm.CommandType = CommadnType.StoredProcedure;

      comm.Parameters.Add(new SqlParameter("@Count ",SqlDbType.Int));

      comm.Parameters["@Count "].Direction = ParameterDirection.Output;

      SqlDataReader sdr = comm.ExecuteReader();

      while(sdr.Reader())

      {

        ……

      }

      sdr.Close();

      //在读完结果集后,再调用ExecuteNonQuery()方法

      comm.ExecuteNonQuery(); 

      int count = (int)comm.Parameters["@UserId"].Value;

      comm.Conection.Close();

    }

  这样一来结果集和输出参数或返回值就都可以获得了。

  还有个非常细小的问题,实际开发过程中,为了代码的复用,会编写DBHelper类,看代码:

  public static SqlCommand GetConn(string sql,params SqlParameter[] sqlParams)

  {

    SqlConnection conn = new SqlConnection("……");

    SqlCommand comm = new SqlCommand(sql,conn);

    //将参数添加到末尾

    comm.Parameters.AddRange(sqlParams);

    try

    {

      conn.Open();

    }catch(SqlException se)

    {

      throw se;

    }

    return comm;

  }

  如此添加的时候会出现问题,有碰到说“给存储过程提供过多的参数的异常”的朋友就知道了,输入输出参数之和刚好和存储过程是一样的,就是一直出运行时异常“给存储过程提供过多的参数的异常”。将

  comm.Parameters.AddRange(sqlParams);

  修改至 comm.Parameters.Add(sqlParams); 

  即可解决掉那个烦人的异常了。