您的位置:首页 > 编程语言 > C#

c#调用带out类型参数的存储过程拿不到返回值的解决办法

2016-05-31 16:55 706 查看
      很平常的一个用法,没遇到过的人不会来看这篇文章,但我遇到了,搜索了,了解了,所以写下了。

      首先,带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);

</pre><p></p><pre>


这是一个典型的小分页的存储过程,针对这特定的表。代码很简单不用多解释,第一句就是取得记录,第二句就是返回记录总数,是对一个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<ProductsType> 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<ProductsType> ProductsTypeList = new List<ProductsType>();

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的内部机制,要求程序是这样的,所以,我们只能按照这个顺序来做
</pre><pre code_snippet_id="1702983" snippet_file_name="blog_20160531_9_4837132" name="code" class="csharp">以上代码正常取得,如果我的总结有错误的地方,希望看到的你别一笑了之,这是重在分享和传递,谢谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息