对于 ADO,使用 SqlDataAdapter.FillSchema 清除标记为输出的 @ReturnValues 和其他存储过程参数
With ADO, using SqlDataAdapter.FillSchema clears @ReturnValues and other stored procedure parameters marked for output
[编辑 - 答案的解释在问题的底部,因为接受的答案中的微妙之处并不完全明显。]
原问题:
我正在寻找一个快速的 'yes this approach should be possible' 答案,然后再做出进一步的努力。
场景:
- 我有一个运行查询的简单 SQL 服务器存储过程。我还想 (1) return 声明为
OUTPUT
的 varchar(100)
参数,以及 (2) 使用 @ReturnValue
到 return 另一个(整数)值.
- 我使用
SqlDatAdapter.DataSet.Fill()
方法从 C# 调用此过程。
- 回到 C# 代码,我可以访问过程参数,但我无法获得
@ReturnValue
或其他 OUTPUT
参数的值。
我在期待什么?
-
SqlDataAdapter
填充过程从 select 抓取数据。这有效,我可以在 C# 中访问这些数据。
- 标记为
OUTPUT
的 SQL 服务器存储过程参数和自动 @ReturnValue
参数的值将在 C# 中可用。
我看到了什么?
- 数据按预期从查询中return编辑。
- C# 中存在 SQL 命令参数,但它们的
.Value
属性为空。
我做了哪些研究?
- 大量搜索包含
SqlDataAdapter
和 @returnvalue
的匹配项。没有显着的阳性结果。
- 仔细阅读与
SqlDataAdapter
相关的旧 SO 问题 - 似乎没有任何内容与我的问题重叠。
- 发布了这个问题。
我需要询问 SO 社区这是否可能。那么 - 是否可以从与 SqlDatAdapter.DataSet.Fill()
一起使用的存储过程中收集 OUTPUT
参数值?
如果答案是肯定的,并且没有简单的示例,那么我将把我的代码缩减为一个有代表性的案例,post 它在这里用于(希望)社区调试。
编辑
感谢@NDJ 和提供的示例代码,我能够确认 SqlDatAdapter.DataSet.Fill()
不会 干扰存储过程 return 值。然后我能够继续发现我的问题是由立即调用 SqlDatAdapter.DataSet.FillScheam()
引起的。这将数据 table 的元数据传送到一个方便的矩阵中,我们可以从 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
}
[编辑 - 答案的解释在问题的底部,因为接受的答案中的微妙之处并不完全明显。]
原问题:
我正在寻找一个快速的 'yes this approach should be possible' 答案,然后再做出进一步的努力。
场景:
- 我有一个运行查询的简单 SQL 服务器存储过程。我还想 (1) return 声明为
OUTPUT
的varchar(100)
参数,以及 (2) 使用@ReturnValue
到 return 另一个(整数)值. - 我使用
SqlDatAdapter.DataSet.Fill()
方法从 C# 调用此过程。 - 回到 C# 代码,我可以访问过程参数,但我无法获得
@ReturnValue
或其他OUTPUT
参数的值。
我在期待什么?
-
SqlDataAdapter
填充过程从 select 抓取数据。这有效,我可以在 C# 中访问这些数据。 - 标记为
OUTPUT
的 SQL 服务器存储过程参数和自动@ReturnValue
参数的值将在 C# 中可用。
我看到了什么?
- 数据按预期从查询中return编辑。
- C# 中存在 SQL 命令参数,但它们的
.Value
属性为空。
我做了哪些研究?
- 大量搜索包含
SqlDataAdapter
和@returnvalue
的匹配项。没有显着的阳性结果。 - 仔细阅读与
SqlDataAdapter
相关的旧 SO 问题 - 似乎没有任何内容与我的问题重叠。 - 发布了这个问题。
我需要询问 SO 社区这是否可能。那么 - 是否可以从与 SqlDatAdapter.DataSet.Fill()
一起使用的存储过程中收集 OUTPUT
参数值?
如果答案是肯定的,并且没有简单的示例,那么我将把我的代码缩减为一个有代表性的案例,post 它在这里用于(希望)社区调试。
编辑
感谢@NDJ 和提供的示例代码,我能够确认 SqlDatAdapter.DataSet.Fill()
不会 干扰存储过程 return 值。然后我能够继续发现我的问题是由立即调用 SqlDatAdapter.DataSet.FillScheam()
引起的。这将数据 table 的元数据传送到一个方便的矩阵中,我们可以从 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
}