带有 varbinary(max) OUTPUT 的 CLR 存储过程失败,但相同的过程与 T-SQL 一样工作
我有一个存储过程:
CREATE PROCEDURE [dbo].[brbackup]
@dataID [nvarchar](max),
@backupdata [varbinary](max) OUTPUT
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [SQLBackupRestore].[StoredProcedures].[BackupStuff]
GO
它映射回这个 CLR 存储过程代码:
public class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void BackupStuff(string dataID, out byte [] backupdata)
{
[..body omitted..]
}
}
这工作得很好,我可以在服务器上的 t-sql 中调用它,如下所示:
declare @backupdata varbinary(max);
exec brbackup "dataIDNumber", @backupdata output;
我得到了预期的输出(@backupdata 中的几兆数据) )。我想做的是通过客户端从 C# 调用它,但这不起作用:
static void Main(string[] args)
{
SqlConnection conn = new SqlConnection("myConnString");
conn.Open();
SqlCommand cmd = new SqlCommand("brbackup", conn);
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@dataID", "dataIDNumber");
SqlParameter p = new SqlParameter("@backupdata",
SqlDbType.VarBinary, -1);
p.Direction = ParameterDirection.Output;
cmd.Parameters.Add(p);
cmd.ExecuteNonQuery();
}
此查询不会给出错误,并且它会运行一段时间(如预期),但是 p.Value
里面除了一个 byte[0]
之外什么都没有。我尝试过将长度设置为 -1 以外的其他值,并将 p.Value
设置为足以容纳结果的 byte[]
,但没有什么乐趣。
然而,奇怪的是,创建一个小的 t-sql 存储过程来包装 CLR 存储过程确实有效:
CREATE PROCEDURE AA_JUST_TESTING
@stuff varbinary(max) output
AS
BEGIN
declare @backupdata varbinary(max);
exec brbackup 'dataIDNumber', @backupdata output;
set @stuff = @backup;
END
GO
然后使用以下 C# 代码调用包装器 AA_JUST_TESTING:
SqlConnection conn = new SqlConnection("myConnString");
conn.Open();
SqlCommand cmd = new SqlCommand("AA_JUST_TESTING", conn);
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter p = new SqlParameter("@stuff",
SqlDbType.VarBinary, -1);
p.Direction = ParameterDirection.Output;
cmd.Parameters.Add(p);
cmd.ExecuteNonQuery();
效果很好。 p.Value
最终得到一个大小正好且填充了正确数据的 byte []
。
所以...除了一个调用 CLR 存储过程和另一个调用 T-SQL 存储过程之外,我看不出有什么区别,即使它们都使用 varbinary(max) 输出
返回值。我正在寻找:
一个合理的解释,指向文档的指针等...告诉我为什么它会这样工作。
某种解决方法,这样我就不必拥有包装器存储过程,并且可以直接从 C# 调用 CLR SP 来完成我需要的事情。
某种
I have a stored procedure:
CREATE PROCEDURE [dbo].[brbackup]
@dataID [nvarchar](max),
@backupdata [varbinary](max) OUTPUT
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [SQLBackupRestore].[StoredProcedures].[BackupStuff]
GO
Which maps back to this CLR Stored procedure code:
public class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void BackupStuff(string dataID, out byte [] backupdata)
{
[..body omitted..]
}
}
This works just fine, I can call it in t-sql on the server just fine like this:
declare @backupdata varbinary(max);
exec brbackup "dataIDNumber", @backupdata output;
I get the expected output (several megabytes of data in @backupdata). What I'd like to do is call this from C# through a client, but this doesn't work:
static void Main(string[] args)
{
SqlConnection conn = new SqlConnection("myConnString");
conn.Open();
SqlCommand cmd = new SqlCommand("brbackup", conn);
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@dataID", "dataIDNumber");
SqlParameter p = new SqlParameter("@backupdata",
SqlDbType.VarBinary, -1);
p.Direction = ParameterDirection.Output;
cmd.Parameters.Add(p);
cmd.ExecuteNonQuery();
}
This query doesn't give an error, and it runs for a while (as expected), but p.Value
has nothing in it but a byte[0]
. I've tried variations of setting the length to something other than -1, and setting p.Value
to a byte[]
large enough to hold the results, but no joy.
However, strangely enough creating a small t-sql stored procedure to wrap around the CLR stored procedure DOES work:
CREATE PROCEDURE AA_JUST_TESTING
@stuff varbinary(max) output
AS
BEGIN
declare @backupdata varbinary(max);
exec brbackup 'dataIDNumber', @backupdata output;
set @stuff = @backup;
END
GO
And then calling the wrapper AA_JUST_TESTING with this C# code:
SqlConnection conn = new SqlConnection("myConnString");
conn.Open();
SqlCommand cmd = new SqlCommand("AA_JUST_TESTING", conn);
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter p = new SqlParameter("@stuff",
SqlDbType.VarBinary, -1);
p.Direction = ParameterDirection.Output;
cmd.Parameters.Add(p);
cmd.ExecuteNonQuery();
Works just peachy. p.Value
winds up with a byte []
of just the right size filled with the correct data.
So... I don't see the difference other than one calls a CLR stored procedure and the other calls a T-SQL stored procedure, even though they're both using a varbinary(max) output
to return the value. I'm looking for:
A plausible explanation, pointer to documentation, etc... that tells me why this works like it does.
Some kind of work-around so I don't have to have the wrapper stored procedure, and can maybe just accomplish what I need calling the CLR SP directly from C#.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
奇怪的。尝试将 C# 代码从: 更改
为:
使用 SqlBinary 作为 C# 例程的返回类型对我有用。
编辑:
好吧,使用 SqlBinary 或 byte[] 都适合我。
您的 varbinary(max) 参数是否称为“@backup”或“@backupdata”?看起来您显示的示例代码同时使用了两者。
即尝试将 : 更改
为 :
Strange. Try changing the C# code from :
To :
Using SqlBinary as the return type of the C# routine works for me.
EDIT :
Well, using either SqlBinary or byte[] both work for me.
Is your varbinary(max) parameter called "@backup" or "@backupdata" ? Looks like the sample code you show uses both.
i.e. try changing :
to :