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

      很平常的一个用法,没遇到过的人不会来看这篇文章,但我遇到了,搜索了,了解了,所以写下了。


      首先,带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的内部机制,要求程序是这样的,所以,我们只能按照这个顺序来做
以上代码正常取得,如果我的总结有错误的地方,希望看到的你别一笑了之,这是重在分享和传递,谢谢。



你可能感兴趣的:(c#,C,Sharp)