【问题标题】:CLR stored procedure with varbinary(max) OUTPUT fails, but same procedure works as T-SQL带有 varbinary(max) OUTPUT 的 CLR 存储过程失败,但与 T-SQL 相同的过程
【发布时间】:2011-12-01 22:36:11
【问题描述】:

我有一个存储过程:

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) output 来返回值。我正在寻找:

  • 一个似是而非的解释、指向文档的指针等...告诉我为什么会这样。

  • 某种变通方法,这样我就不必拥有包装存储过程,并且可以直接从 C# 中完成我需要调用 CLR SP 的工作。

【问题讨论】:

    标签: c# sql-server-2008 tsql sqlclr


    【解决方案1】:

    奇怪。尝试从以下位置更改 C# 代码:

    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void BackupStuff(string dataID, out byte [] backup)
    {
       [..body omitted..]
    }
    

    收件人:

    using System.Data.SqlTypes;
    ...
    
        [Microsoft.SqlServer.Server.SqlProcedure]
        public static void BackupStuff(string dataID, out SqlBinary backup)
        {
           [..body omitted..]
           byte[] result = ... // get byte array to return
           backup = new SqlBinary(result);
        }
    

    使用 SqlBinary 作为 C# 例程的返回类型适合我。

    编辑: 好吧,使用 SqlBinary 或 byte[] 都对我有用。 您的 varbinary(max) 参数是否称为 "@backup" 或 "@backupdata" ?看起来您显示的示例代码同时使用了两者。 即尝试更改:

      SqlParameter p = new SqlParameter("@backupdata", 
                                               SqlDbType.VarBinary, -1);
    

    到:

      SqlParameter p = new SqlParameter("@backup", 
                                               SqlDbType.VarBinary, -1);
    

    【讨论】:

    • 对不起,代码的“为公众消费擦洗”不一致。它们都被命名为……专有的。 :) 我会修正上面的例子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多