【问题标题】:SQL Server 2012 CLR Assembly - Parameter Counts Don't MatchSQL Server 2012 CLR 程序集 - 参数计数不匹配
【发布时间】:2016-05-22 09:55:03
【问题描述】:

小历史:我们已经成功(2 年前)为 SQL Server 构建了 .NET CLR 代码,编译为程序集,并加载到 SQL Server 2008 R2 Enterprise 数据库中。然后我们创建了 TSQL 对象来调用 CLR 代码。自从第一次安装以来,它一直没有问题,我们多年来对其进行了修改,没有出现问题。

今天:我们需要修改CLR代码。在 Visual Studio 中执行此操作不会导致编译到程序集出现问题。 TSQL 引用的函数的签名根本没有改变(所有参数、参数类型等都没有改变)。修改是重构函数中的一些底层代码并创建几个新函数(所有这些函数都是私有静态的,不会在 TSQL 中被引用)。我们现在使用的是 SQL Server 2012 Enterprise(升级在 2015 年中期顺利进行,数据库现在处于 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 可能会发生一些事情。我尝试编译针对 .NET 3.5 和 .NET 4.0 以及针对 2008 R2 数据库和 2012 数据库的程序集(所以 4 个组合)。数据库本身使用 .NET 4.0,因为它处于 2012 兼容模式。

数据库确实启用了 CLR。​​

关于如何使它工作的任何想法?到目前为止,谷歌让我失望了。

编辑

确切的函数签名(直接从 Visual Studio 中复制)如下(是的,很多已被传递到此函数中,而不是让 CLR 代码查询数据,在我们的测试中,这表明性能比传递更差一切都在)。

[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)] 公共静态 SqlDouble udfGetCellValueCLR( int MetricID, 字符串 CSVDimensionList, 字符串聚合SQLString, 字符串 DateColumnForAverage, bool TimeFrameIsAVariance, bool TimeFrameIsAPlan, 布尔 IsAnAverage, bool TimeFrameIsPercentOfTotal, bool AggregationAllowsPercentOfTotal, bool PlanAggregationAllowsPercentOfTotal, bool MetricIsAPercentage, 诠释好方向, int PlanMetricID, 字符串 PlanAggregationSQLString, 整数开始日期ID, int EndDateID, bool NumeratorIsAPlan, bool NumeratorIsAnAverage, int NumeratorStartDateID, int NumeratorEndDateID, 字符串 NumeratorDateColumnForAverage, bool DenominatorIsAPlan, 布尔分母是平均值, int DenominatorStartDateID, int DenominatorEndDateID, 字符串 DenominatorDateColumnForAverage, SqlString 特殊聚合 )

TSQL CREATE FUNCTION 语句如下(这是出错的语句)。

创建函数 [be].[udfGetCellValueCLR]( @MetricID [int], @CSVDimensionList [nvarchar](4000), @AggregationSQLString [nvarchar](4000), @DateColumnForAverage [nvarchar](4000), @TimeFrameIsAVariance [位], @TimeFrameIsAPlan [位], @IsAnAverage [位], @TimeFrameIsPercentOfTotal [位], @AggregationAllowsPercentOfTotal [位], @PlanAggregationAllowsPercentOfTotal [位], @MetricIsAPercentage [位], @GoodDirection [int], @PlanMetricID [int], @PlanAggregationSQLString [nvarchar](4000), @StartDateID [int], @EndDateID [int], @NumeratorIsAPlan [位], @NumeratorIsAnAverage [位], @NumeratorStartDateID [int], @NumeratorEndDateID [int], @NumeratorDateColumnForAverage [nvarchar](4000), @DenominatorIsAPlan [位], @DenominatorIsAnAverage [位], @DenominatorStartDateID [int], @DenominatorEndDateID [int], @DenominatorDateColumnForAverage [nvarchar](4000), @SpecialAggregation [nvarchar](4000) ) 返回 [float] 并作为调用者执行 作为 外部名称 [EMMACustomCode].[UserDefinedFunctions].[udfGetCellValueCLR] 走

【问题讨论】:

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

标签: sql-server sql-server-2008-r2 sql-server-2012 sql-server-data-tools sqlclr


【解决方案1】:

如果参数列表不匹配,那么实际上Assembly(已经加载到SQL Server中的那个)和CREATE FUNCTION语句之间是有区别的。

如果您使用 Visual Studio / SQL Server Data Tools (SSDT) 来生成程序集和 T-SQL 包装器对象,那么您需要注意 SSDT 生成两种类型的 SQL 脚本:创建脚本和发布/部署脚本。

创建脚本不假设它们将被部署到的当前状态。如果目标数据库已经存在,他们将删除它,然后重新创建数据库并加载所有对象(程序集和 T-SQL 包装器对象)。并不总是生成“{ProjectName}_Create.sql”脚本。 “项目属性”的“项目设置”选项卡上通常有一个选项(复选框)来启用此脚本的创建。此脚本不会被部署,它只是供您获取。

发布/部署脚本是增量部署。这些是由 SSDT 创建的,首先检查目标数据库的当前状态,然后只进行必要的更改以使目标达到项目中的状态(即在生成的.dacpac 文件中)。

如果您需要确保在您的项目中有代码的一切脚本,那么请确保在“项目”中启用“创建脚本(.sql 文件)”选项属性” | “Project Settings”,做一个Build / Rebuild(不需要做一个Publish),然后检查“Build output path”的活动配置。

如果您只需要更改,则可以使用“{ProjectName}.sql”脚本。但是,您实际上需要执行 Publish(甚至是对 dev ——“Start without Debugging”),以便启动检查目标数据库当前状态的进程。即使那样,如果没有更改,增量发布/部署脚本也不会创建。

您不需要 Visual Studio 来生成发布脚本。您可以使用SqlPackage.exe 实用程序通过命令行执行此操作(操作将是“脚本”)。

【讨论】:

  • 谢谢。我没有做的是发布来获取发布/部署脚本。我刚刚做了一个构建。这意味着我引用了一个旧的发布/部署脚本,而根本没有查看文件创建时间戳。非常感谢您的帮助!
  • 没问题。很高兴信息/问题能够为您指明正确的方向:)。我只是在最后添加了一些关于生成发布脚本的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-28
  • 2011-09-15
  • 1970-01-01
  • 2015-03-05
  • 1970-01-01
  • 2019-07-26
相关资源
最近更新 更多