一点历史:我们已成功(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)] public static SqlDouble udfGetCellValueCLR( int MetricID, string CSVDimensionList, string AggregationSQLString, string DateColumnForAverage, bool TimeFrameIsAVariance, bool TimeFrameIsAPlan, bool IsAnAverage, bool TimeFrameIsPercentOfTotal, bool AggregationAllowsPercentOfTotal, bool PlanAggregationAllowsPercentOfTotal, bool MetricIsAPercentage, int GoodDirection, int PlanMetricID, string PlanAggregationSQLString, int StartDateID, int EndDateID, bool NumeratorIsAPlan, bool NumeratorIsAnAverage, int NumeratorStartDateID, int NumeratorEndDateID, string NumeratorDateColumnForAverage, bool DenominatorIsAPlan, bool DenominatorIsAnAverage, int DenominatorStartDateID, int DenominatorEndDateID, string DenominatorDateColumnForAverage, SqlString SpecialAggregation )
下面是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) ) RETURNS [float] WITH EXECUTE AS CALLER AS EXTERNAL NAME [EMMACustomCode].[UserDefinedFunctions].[udfGetCellValueCLR] GO
答案 0 :(得分:2)
如果参数列表不匹配,那么Assembly(已经加载到SQL Server中的那个)和CREATE FUNCTION
语句之间实际上存在差异。
如果您使用Visual Studio / SQL Server数据工具(SSDT)生成Assembly和T-SQL包装器对象,那么您需要知道SSDT生成两种类型的SQL脚本:创建脚本,以及发布/部署脚本。
创建脚本不会假设它们将部署的当前状态。如果目标数据库已经存在,它们将删除它,然后重新创建数据库并加载所有对象(Assembly和T-SQL包装器对象)。 " {ProjectName} _Create.sql"脚本并不总是生成。在"项目设置"上通常有一个选项(复选框)。 "项目属性"的选项卡启用此脚本的创建。这个脚本没有部署,只是你可以抓住它。
发布/部署脚本是增量部署。这些是由SSDT创建的,首先检查目标数据库的当前状态,并仅进行必要的更改以使目标达到项目中的状态(即生成的.dacpac
文件中)。 p>
如果你需要确保你的项目中有代码的所有脚本,那么请确保拥有"创建脚本(.sql文件)&#34 ;在"项目属性"中启用了选项| "项目设置",进行构建/重建(不需要发布),然后检查"构建输出路径"用于活动配置。
如果您只想要更改,那么您可以使用" {ProjectName} .sql"脚本。但是,您需要实际执行发布(即使是开发 - "启动时不进行调试")以启动检查目标数据库当前状态的进程。即使这样,如果没有更改,也不会创建增量发布/部署脚本。
您不需要Visual Studio来生成发布脚本。您可以使用SqlPackage.exe实用程序通过命令行执行此操作(操作将是"脚本")。