使用存储过程会给程序设计上带来很多的方便,也可使程序开发师的分工更加明确,最主要的是可以提高系统性能。前些日子在下在开发过程中遇到一些问题,现在写下来分享分享经验,希望能给你们节约些时间。
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);
即可解决掉那个烦人的异常了。