C# 使用ADO,使用SqlDataAdapter.FillSchema清除@ReturnValues和其他标记为输出的存储过程参数

C# 使用ADO,使用SqlDataAdapter.FillSchema清除@ReturnValues和其他标记为输出的存储过程参数,c#,sql-server,sqldataadapter,C#,Sql Server,Sqldataadapter,[编辑-答案的解释位于问题的底部,因为从已接受的答案来看,微妙之处并不完全明显。] 原始问题: 我正在寻找一个快速的“是的,这种方法应该是可行的”答案,然后再进一步努力 情景: 我有一个运行查询的简单SQL Server存储过程。我还希望1返回一个声明为输出的varchar100参数,2使用@ReturnValue返回另一个整数值。 我使用SqlDatAdapter.DataSet.Fill方法从C调用这个过程。 回到C代码中,我可以访问过程参数,但无法获取@ReturnValue或其他输出参数

[编辑-答案的解释位于问题的底部,因为从已接受的答案来看,微妙之处并不完全明显。]

原始问题:

我正在寻找一个快速的“是的,这种方法应该是可行的”答案,然后再进一步努力

情景:

我有一个运行查询的简单SQL Server存储过程。我还希望1返回一个声明为输出的varchar100参数,2使用@ReturnValue返回另一个整数值。 我使用SqlDatAdapter.DataSet.Fill方法从C调用这个过程。 回到C代码中,我可以访问过程参数,但无法获取@ReturnValue或其他输出参数的值。 我在期待什么

SqlDataAdapter填充过程以从select获取数据。这是可行的,我可以用C语言访问这些数据。 标记为输出的SQL Server存储过程参数的值,以及在C中可用的自动@ReturnValue参数。 我看到了什么

数据按预期从查询中返回。 SQL命令参数在C中存在,但其.Value属性为空。 我做了什么研究

大量的谷歌搜索包含SqlDataAdapter和@returnvalue的点击。没有明显的积极结果。 仔细阅读与SqlDataAdapter相关的旧SO问题-似乎没有任何问题与我的问题重叠。 发布了这个问题。 我需要问问SO社区这是否可行。So-是否可以从与SqlDatAdapter.DataSet.Fill一起使用的存储过程中收集输出参数值

如果答案是肯定的,并且没有简单的例子,那么我将把我的代码缩减到一个有代表性的案例中,并将其发布在这里,希望社区能够进行调试

编辑 由于@NDJ和提供的示例代码,我能够确认SqlDatAdapter.DataSet.Fill不会干扰存储过程返回值。然后,我发现问题是由对SqlDatAdapter.DataSet.FillScheam的即时调用引起的。这将数据表的元数据传递到一个方便的矩阵中,我们可以从C访问该矩阵,这是我的用例的一部分

但是,FillSchema会清除存储过程参数值。在我的代码中,我试图在调用FillSchema之后收集存储过程输出参数值,这就是我看到的原因。我找不到关于这一点的任何文件

如果您的代码看起来像这样,它就会工作

    da.Fill(ds);

    var returnVal = returnParam.Value; // value as expected

    da.FillSchema(ds, SchemaType.Source);
如果您的代码看起来像这样,它将无法工作

    da.Fill(ds);

    da.FillSchema(ds, SchemaType.Source);

    var returnVal = returnParam.Value; // value reset by prev line !!!!
是的,你可以

Create PROCEDURE TestSP
    @test varchar(max) output
AS
BEGIN
    select @test = 'abc'
    select top 10 * from MyTable
    return 4

END




using (SqlConnection connection = new SqlConnection(conString))
        {
            connection.Open();

            SqlCommand cmd = new SqlCommand("TestSP", connection);
            cmd.CommandType = CommandType.StoredProcedure;

            SqlParameter param = new SqlParameter("@test", SqlDbType.VarChar, -1);
            param.Direction = ParameterDirection.Output;

            var returnParam = cmd.Parameters.Add("@Return", SqlDbType.Int);
            returnParam.Direction = ParameterDirection.ReturnValue;

            cmd.Parameters.Add(param);

            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataSet ds = new DataSet();
            da.Fill(ds);

            var returnVal = returnParam.Value; //4
            var output = param.Value; // abc
            var data = ds.Tables[0].Rows[0][0];  //data from my table
        }

“我没有理由意识到它不起作用。”克劳科德感谢隧道中的那道正光线!你有一个例子的链接吗?我手头没有。但是,如果存储过程正在设置输出并返回值,则该命令应填充参数。您还必须确保您正在适配器中查看正确的命令。参数的方向默认为输入。您需要设置为output:@jdweng-谢谢,我相信我已经准备好了,特别是因为在我设置C端输出参数的大小之前,我看到一个异常,关于size=0无效。我已将您的答案标记为正确。在我的代码中,我立即调用da.FillSchemads,SchemaType.Source;在打电话给da.fill之后。实验表明,FillSchema调用清除过程输出变量。谁知道呢我当然没有这样做:经过一段时间的思考,我直觉如下:从C和SQL Svr之间的对话来看,SQL Svr只是运行了一个存储过程,并将结果作为“执行”存储过程的标准调用返回。聪明的地方在于C必须要求SQLSVR为之前的输出提供模式。实现这一点的方法可能是调用SQL Server为此包含的一些特殊存储过程。因此,如果给定的C只是执行了一个与我原来的存储过程不同的存储过程,那么清除第一个存储过程的输出变量似乎是明智的。