【问题标题】:T-SQL cannot find CLR function in assembly - no namespace?T-SQL 在程序集中找不到 CLR 函数 - 没有命名空间?
【发布时间】:2017-06-20 23:54:45
【问题描述】:

我们正在移植一个 SQL Server 数据库,其中包括一个带有日期函数的 CLR 程序集(开发人员早已离开)。我从 DLL 创建了程序集(它在 sys.assemblies 中列出):

CREATE ASSEMBLY ArkaDB FROM 'C:\Temp\ArkaDB.dll' WITH PERMISSION_SET = SAFE;

但是当我尝试为 GetOIDate 函数创建 SQL 存储过程时:

create FUNCTION [dbo].[GetOIDate](@ActivityDate [datetime])
RETURNS [datetime] WITH EXECUTE AS CALLER
AS 
EXTERNAL NAME [ArkaDB].[ArkaDB.UserDefinedFunctions].[GetOIDate]

它给出错误“消息 6505,级别 16,状态 2,过程 GetOIDate,第 2 行 在程序集“ArkaDB”中找不到类型“ArkaDB.UserDefinedFunctions”。”

您可以在下面的 ILSpy 屏幕截图中看到 DLL 结构和函数代码。注意命名空间的破折号“-”。从this 的问题来看,我们应该在外部名称规范中包含一个命名空间。但是如果没有命名空间呢?答案here 表明您只需提供类似“EXTERNAL NAME [SqlClr].Math.[Add]”的类。我已经尝试了所有我能想到的变体,它们都给出了相同的找不到错误:

EXTERNAL NAME [ArkaDB].[ArkaDB.UserDefinedFunctions].[GetOIDate]
EXTERNAL NAME [ArkaDB].UserDefinedFunctions.[GetOIDate]
EXTERNAL NAME [ArkaDB].[.UserDefinedFunctions].[GetOIDate]
EXTERNAL NAME [ArkaDB].[-.UserDefinedFunctions].[GetOIDate]
EXTERNAL NAME [ArkaDB].[''.UserDefinedFunctions].[GetOIDate]
EXTERNAL NAME [ArkaDB].[ .UserDefinedFunctions].[GetOIDate]

有什么想法吗?我们正在运行 SQL Server 2012,而 DLL 最初是为 2008 R2 开发和安装的。 ILSpy for ArkaDB DLL

编辑:对于 srutzky,这里是 ILSpy UserDefinedFunctions class 中的公共类定义

【问题讨论】:

  • 这个——EXTERNAL NAME [ArkaDB].UserDefinedFunctions.[GetOIDate]——应该是正确的,或者你可以在类名周围加上方括号:EXTERNAL NAME [ArkaDB].[UserDefinedFunctions].[GetOIDate]。该类是否标记为“公共”?
  • 感谢您的回复。是的,该课程是公开的——请参见上面添加的图片。您对应该正确的格式是正确的。如果我在旧数据库中编写 SQL 函数创建脚本,它会生成“EXTERNAL NAME [ArkaDB].[UserDefinedFunctions].[GetOIDate]”。但是,当在新服务器中运行时,这会产生类似的错误“在程序集 'ArkaDB' 中找不到类型 'UserDefinedFunctions'”。我的下一步是尝试在 Visual Studio 中重建 DLL,但这对于遗留代码来说总是令人担忧:我有正确的源代码吗? VS版本有问题吗?
  • 您的名字与 sys.assembl* 表中的名字匹配吗?如此处所述:docs.microsoft.com/en-us/sql/t-sql/statements/… 在页面上搜索 sys.
  • 这里只是猜测,但您可以尝试使用DATETIME2 而不是DATETIME 作为输入参数和返回值类型吗?
  • 您是否 100% 确定您加载到 SQL Server 2012 中的 DLL 与用于加载 2008 R2 的 DLL 完全相同?您应该使用以下查询比较在content 列中找到的值:SELECT DATALENGTH([content]) AS [bytes], * FROM sys.assembly_files WHERE [name] LIKE N'%ArkaDB%' AND [file_id] = 1;。如果它们具有相同的字节数,那么您需要比较内容。您可以将两个服务器中的内容值复制并粘贴到查询中,在其中将它们创建为VARBINARY(MAX)VARCHAR(MAX) 变量,然后查看它们是否相等。

标签: sql-server dll .net-assembly sqlclr


【解决方案1】:

很遗憾,我无法发表评论(声誉不够),所以让我们尝试回答一下:

您写道:“如果我在旧数据库中编写 SQL 函数创建脚本,它会生成“EXTERNAL NAME [ArkaDB].[UserDefinedFunctions].[GetOIDate]”。”。如果您从旧数据库(我假设它在哪里工作)编写程序集脚本,然后以这种方式部署到新数据库会怎样。

类似:

CREATE ASSEMBLY ArkaDB FROM binary_representation WITH PERMISSION_SET = SAFE;

这样您至少应该能够部署它。如果没有命名空间存在,在你的程序集中,创建函数应该像 srutzky 说的那样:

CREATE FUNCTION [dbo].[GetOIDate](@ActivityDate [datetime])
RETURNS [datetime] WITH EXECUTE AS CALLER
EXTERNAL NAME [ArkaDB].[UserDefinedFunctions].[GetOIDate]

请告诉我们进展如何。

尼尔斯

【讨论】:

    猜你喜欢
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-16
    • 1970-01-01
    • 2013-11-17
    • 2014-01-01
    相关资源
    最近更新 更多