很平常的一个用法,没遇到过的人不会来看这篇文章,但我遇到了,搜索了,了解了,所以写下了。
首先,带out参数类型存储过程我们写成这样
create procedure winne_Get_ProductsGuiGeFenYe
@pageSize int,
@pageNum int,
@total int output
as
select top (@pageSize) * from [productsGuiGe] where RowID not in(select top ((@pageNum-1)*@pageSize) rowID from dbo.ProductsGuiGe order by RowID) order by RowID;
set @total=(select count(1) from ProductsGuiGe);
这是一个典型的小分页的存储过程,针对这特定的表。代码很简单不用多解释,第一句就是取得记录,第二句就是返回记录总数,是对一个out型参数复制
再来看c#的调用,因为要获取到数据和总条数两个,所以不能用SqlCommand.ExcuteNonQuery来执行这个procedure,我们选择使用SqlCommand.ExcuteReader()来调用,那么问题来了,如果你遇到过:那就是,取得到记录集,就是out参数的@total返回值一直的空的null,就是这个现象。然后在数据库管理界面去执行你的存储过程又能够取到,因此我们确保我们的存储过程是没有问题的。
先看c#代码
public static SqlDataReader EcuteReader(string sql, CommandType ctType, SqlParameter[] paras)
{
SqlConnection sqlcon = new SqlConnection(conString);
sqlcon.Open();
using (SqlCommand scmd = new SqlCommand(sql, sqlcon))
{
scmd.CommandType = ctType;
if (paras.Length > 0)
{
scmd.Parameters.AddRange(paras);
}
return scmd.ExecuteReader();
}
}
--------------------------------------------------调用代码-------------------------------------------------------
public SqlDataReader GetProductsTypesList(string sql,CommandType ctType,SqlParameter[] paras)
{
return SqlHelper.EcuteReader(sql, ctType, paras);
}
--------------------------------------------------使用的代码---------------------------------------------------
public List GetProductsTypesList(out int total,int pageSize,int pageNum)
{
ProductsDal pd = new ProductsDal();
SqlParameter[] sp = new SqlParameter[3];
sp[0]=new SqlParameter("@pageSize",SqlDbType.Int);
sp[0].Value = pageSize;
sp[1] = new SqlParameter("@pageNum", SqlDbType.Int);
sp[1].Value = pageNum;
sp[2] = new SqlParameter("@total", SqlDbType.Int);
sp[2].Direction=ParameterDirection.Output;
SqlDataReader sqldr = pd.GetProductsTypesList("winne_Get_ProductsGuiGeFenYe", CommandType.StoredProcedure, sp);
List ProductsTypeList = new List();
while (sqldr.Read())
{
ProductsType pt = new ProductsType();
pt.RowId = int.Parse(sqldr["RowID"].ToString());
pt.FatherName = sqldr["FatherName"].ToString();
pt.TypeDanwei = sqldr["cp_danwei"].ToString();
pt.TypeName = sqldr["GuiGeName"].ToString();
pt.TypeID = sqldr["GuiGeID"].ToString();
pt.Statue = sqldr["shenchan_status"].ToString();
ProductsTypeList.Add(pt);
}
sqldr.Close();
sqldr.Dispose();
total = int.Parse(sp[2].Value.ToString());//位置
return ProductsTypeList;
}
1.首先,要用EcuteReader的话,必须注意,SqlConnection类型的变量不能在using里面使用,如代码段中所示 SqlConnection sqlcon = new SqlConnection(conString);因为返回值sqldatareader在读取的时候是延迟分配,用的时候才会来查询数据库,需要用到这个连接的,放using里面会被方法体出来的时候就被释放掉。
2.上面一点保证了能够正常通过SqlDataReader拿到返回的记录
3.接下来就是out类型参数,一定要等到ExcuteReader方法返回的SqlDataReader关闭掉以后,参会填充值,所以位置很重要,要放在
sqldr.Close();
sqldr.Dispose();
total = int.Parse(sp[2].Value.ToString());//位置
这样,就能够正常拿到了
3.可能有朋友觉得是不是存储过程里面的两句话的顺序导致的,把out参数赋值放在前面,是不是就可以把接受值放前面了,其实不然,我尝试过这样,答案是否定的,这是ado.net的内部机制,要求程序是这样的,所以,我们只能按照这个顺序来做
以上代码正常取得,如果我的总结有错误的地方,希望看到的你别一笑了之,这是重在分享和传递,谢谢。