SQL Server 2012 CLR程序集 - 参数计数不匹配

3

一点历史: 两年前,我们成功地为SQL Server构建了.NET CLR代码,编译成一个程序集,并将其加载到SQL Server 2008 R2 Enterprise数据库中。然后,我们创建了TSQL对象来调用CLR代码。自从第一次安装以来,这一切都没有出现问题,并且我们在过去的几年中进行了修改而没有出现问题。

今天: 我们需要修改CLR代码。在Visual Studio中进行此操作不会导致编译程序集时出现任何问题。被TSQL引用的函数的签名没有发生任何变化(所有参数、参数类型等都没有发生变化)。修改是为了重新设计一些函数的基础代码并创建一些新函数(所有这些函数都是私有静态的,不会在TSQL中被引用)。我们现在使用的是SQL Server 2012 Enterprise(升级于2015年中顺利进行,并且现在DB处于2012兼容模式)。

我可以成功地在SQL Server中删除和重新创建程序集。当重新创建依赖程序集的TSQL对象时,一些绑定到CLR函数签名的对象没有问题,但是被重新设计的一个对象无法重新创建。错误信息如下:

Msg 6550, Level 16, State 2, Procedure udfGetCellValueCLR, Line 2
CREATE FUNCTION failed because parameter counts do not match.

参数没有任何变化。当我查看Visual Studio自动生成的TSQL代码来创建TSQL函数,并尝试使用该代码创建一个函数时,它也会出现相同的错误消息,因此我知道TSQL代码是正确的(没有遗漏参数、顺序、类型等)。
感觉可能与升级到2012的DB有关。我已经尝试编译程序集,将其针对.NET 3.5和.NET 4.0以及针对2008 R2数据库和2012数据库进行定位(因此有4个组合)。DB本身正在使用.NET 4.0,因为它处于2012兼容模式下。
数据库确实启用了CLR。
有什么想法可以让这个工作吗?目前谷歌没有帮到我。
编辑
确切的函数签名(直接从Visual Studio复制)如下(在我们的测试中,已将很多内容传递给了CLR代码查询数据,显示出比传递所有内容更差的性能)。
TSQL CREATE FUNCTION语句如下(这是出错的语句)。
CREATE FUNCTION [be].[udfGetCellValueCLR]( @MetricID [int], @CSVDimensionList [nvarchar](4000), @AggregationSQLString [nvarchar](4000), @DateColumnForAverage [nvarchar](4000), @TimeFrameIsAVariance [bit], @TimeFrameIsAPlan [bit], @IsAnAverage [bit], @TimeFrameIsPercentOfTotal [bit], @AggregationAllowsPercentOfTotal [bit], @PlanAggregationAllowsPercentOfTotal [bit], @MetricIsAPercentage [bit], @GoodDirection [int], @PlanMetricID [int], @PlanAggregationSQLString [nvarchar](4000), @StartDateID [int], @EndDateID [int], @NumeratorIsAPlan [bit], @NumeratorIsAnAverage [bit], @NumeratorStartDateID [int], @NumeratorEndDateID [int], @NumeratorDateColumnForAverage [nvarchar](4000), @DenominatorIsAPlan [bit], @DenominatorIsAnAverage [bit], @DenominatorStartDateID [int], @DenominatorEndDateID [int], @DenominatorDateColumnForAverage [nvarchar](4000), @SpecialAggregation [nvarchar](4000) ) 返回[float],使用CALLER权限执行 作为外部名称[EMMACustomCode]的[UserDefinedFunctions].[udfGetCellValueCLR] GO

2
请提供出现错误的方法签名和确切的“CREATE FUNCTION”语句。 - Solomon Rutzky
已添加方法签名和CREATE FUNCTION代码 - thomas
签名至少似乎匹配。你尝试在另一个实例上加载相同的程序集并运行特定的“CREATE FUNCTION”语句了吗?你甚至可以下载SQL Server Express 2012 LocalDB的副本,进行轻量级安装以进行测试。我认为我们需要确保你在Visual Studio中查看的代码就是编译为该程序集的代码。我看到只有一个参数是Sql*类型。我怀疑这不是问题,但这是一个区别。理想情况下,所有参数都应该是SqlBooleanSqlStringSqlInt32等类型。 - Solomon Rutzky
我在我们的2012 DEV服务器上创建了两个全新的数据库(一个是2012模式,另一个是2008模式),里面什么都没有。将程序集加载到其中,在两种情况下,“CREATE FUNCTION”都失败了,出现了相同的错误。我使用iLSpy打开了从VS编译的DLL,看到了我期望在DLL中看到的代码。我一直在使用TSQL中的HEX加载DLL,接下来将尝试使用文件路径加载选项。 - thomas
我认为HEX应该是没问题的,那是我一直使用的。但如果问题确实是升级引起的,那么如果您创建一个新实例(即非升级!),这将更清晰地看到。这就是我为什么建议使用LocalDB的原因。它是一个小型的单个.msi下载,安装起来非常快速(没有服务等)。 - Solomon Rutzky
显示剩余9条评论
1个回答

2
如果参数列表不匹配,则实际上存在一个差异,即已加载到 SQL Server 中的程序集(Assembly)与 CREATE FUNCTION 语句之间的差异。
如果您正在使用 Visual Studio / SQL Server Data Tools (SSDT) 生成程序集和 T-SQL 封装对象,则需要注意 SSDT 生成两种类型的 SQL 脚本:创建脚本和发布 / 部署脚本。 创建脚本 不会假设它们将部署到何处的当前状态。它们将删除目标数据库(如果已存在),然后重新创建数据库并加载所有对象(程序集和 T-SQL 封装对象)。"{ProjectName}_Create.sql" 脚本并不总是会生成。通常在 "项目属性" 的 "项目设置" 选项卡上有一个复选框来启用此脚本的创建。这个脚本不会被部署,只是供您使用。 发布 / 部署脚本 是增量部署。SSDT 首先检查目标数据库的当前状态,然后仅进行必要的更改,以使目标达到项目中所包含的状态(即在生成的 .dacpac 文件中的状态)。
如果您需要确保在项目中有代码的所有内容都已编写脚本,则请确保在“项目属性”|“项目设置”中启用“创建脚本(.sql文件)”选项,进行构建/重建(无需发布),然后检查活动配置的“生成输出路径”。
如果您只需要更改内容,则可以使用“{ProjectName}.sql”脚本。但是,您需要实际执行发布操作(即使是到dev——“不带调试启动”),以便开始检查目标数据库的当前状态的过程。即使这样,如果没有更改,则增量发布/部署脚本也不会被创建。
您不需要使用Visual Studio来生成发布脚本。您可以使用SqlPackage.exe实用程序通过命令行来完成(操作将是“脚本”)。

1
谢谢。我没有成功地发布以获取发布/部署脚本。我只是进行了构建。这意味着我正在引用旧的发布/部署脚本,而且根本没有查看文件创建时间戳。非常感谢您的帮助! - thomas
没问题。很高兴这些信息/问题能够指引你朝着正确的方向 :). 我刚刚在结尾处添加了一些关于生成发布脚本的信息。 - Solomon Rutzky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接