SQL CLR 问题:CREATE PROCEDURE 失败,因为参数计数不匹配

SQL CLR issue: CREATE PROCEDURE failed because parameter counts do not match

我确实检查了 this,但问题似乎不是类型不匹配。

我正在尝试使用 CLR 从 blob 数据转换回文件。下面是c#代码转换为dll并使用汇编存储。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;


namespace CLRProcedures
{
   public class WriteFile
    {
        [SqlFunction]
        public static SqlInt32 WriteToFile(SqlBytes binary, SqlString path, SqlBoolean append)
        {
            try
            {
                if (!binary.IsNull && !path.IsNull && !append.IsNull)
                {
                    var dir = Path.GetDirectoryName(path.Value);
                    if (!Directory.Exists(dir))
                        Directory.CreateDirectory(dir);
                    using (var fs = new FileStream(path.Value, append ? FileMode.Append : FileMode.OpenOrCreate))
                    {
                        byte[] byteArr = binary.Value;
                        for (int i = 0; i < byteArr.Length; i++)
                        {
                            fs.WriteByte(byteArr[i]);
                        };
                    }
                    return 1;
                }
                else
                   return 0;
            }
            catch (Exception ex)
            {
                return -2;
            }
        }
    }
}

SQL 查询如下:

CREATE ASSEMBLY FileOutput from 'c:\dlls\CLRProcedures.dll' WITH PERMISSION_SET = SAFE 

CREATE PROCEDURE FileOutput
@file varbinary(max),
@filepath nvarchar(4000),
@append bit,
@message int OUTPUT    
AS    
EXTERNAL NAME FileOutput.[CLRProcedures.WriteFile].WriteToFile

这会引发错误:'CREATE PROCEDURE failed because parameter counts do not match.'

我已经从 here 重新验证了是否存在类型不匹配但没有。我哪里会出错?我试图更改 return 类型的 c# 代码但同样的问题。

谢谢

您需要将 WriteToFile 函数的 OUTPUT 参数添加到 return 值

[SqlFunction]
public static void WriteToFile(SqlBytes binary, SqlString path, SqlBoolean append,out SqlInt32 message)
    {
        try
        {
            if (!binary.IsNull && !path.IsNull && !append.IsNull)
            {
                var dir = Path.GetDirectoryName(path.Value);
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                using (var fs = new FileStream(path.Value, append ? FileMode.Append : FileMode.OpenOrCreate))
                {
                    byte[] byteArr = binary.Value;
                    for (int i = 0; i < byteArr.Length; i++)
                    {
                        fs.WriteByte(byteArr[i]);
                    };
                }
                message = 1;
            }
            else
                message = 0;
        }
        catch (Exception ex)
        {
            message = -2;
        }
    }

更多详情:CLR Stored Procedures

您忽略了错误消息的内容:

CREATE PROCEDURE failed because parameter counts do not match (emphasis added)

问题是参数“count”,而不是任何特定参数“type”。您在方法签名中有 3 个输入参数,但在 CREATE PROCEDURE 语句中指定了 4 个参数。

您的选择是:

  1. 按照 Naji 的建议添加第四个参数,在 C# 代码中声明为 out,并将 return 更改为设置 message 变量,这将匹配您已定义 4 个参数。
  2. 或者,您可以保持 C# 代码不变,并以与常规 T-SQL 存储过程 return 值相同的方式获取 return 值:
    DECLARE @ReturnValue INT;
    
    EXEC @ReturnValue = dbo.FileOutput 0x1234, N'path', 1;
    
    SELECT @ReturnValue;
    
  3. 或者,您甚至可以通过简单地将 T-SQL CREATE 对象语句更改为:
    CREATE FUNCTION dbo.FileOutput
    (
      @File VARBINARY(MAX),
      @FilePath NVARCHAR(4000),
      @Append BIT
    )
    RETURNS INT
    AS EXTERNAL NAME ...
    
    并按如下方式使用:
    DECLARE @ReturnValue INT;
    
    SET @ReturnValue = dbo.FileOutput(0x1234, N'path', 1);
    
    SELECT @ReturnValue;
    
    (从技术上讲,作为 return 是 INT / Int32 的标量函数,您甚至可以使用上面选项 2 中所示的相同存储过程语法来执行它)

另外:

  1. 如果您正在创建一个过程,您应该使用 SqlProcedure 而不是 SqlFunction.
  2. 修饰 C# WriteToFile 方法
  3. SqlBytes 类型提供了一个 Stream 属性 ,它是一个更有效的实际流,而不是将整个二进制值迭代为 byte[]读取该值的方式。只需将 binary.Stream 复制到文件流即可完成:-)
  4. 始终指定模式名称(对于模式绑定对象),无论是在 CREATE 语句、SELECTEXEC 等中

有关使用 SQLCLR 的更多信息,请访问:SQLCLR Info