创建CleanFile CLR函数报错 T-SQL与CLR返回值类型不匹配
问题背景
此前开发的多个CLR DLL均可正常运行,最新开发的CLR DLL在创建函数时持续报错,调整过多种字符串长度设置(包括nvarchar(MAX))、核对过CLR参数数据类型映射规则后仍未解决。
具体报错信息:
CREATE FUNCTION for "CleanFile" failed because T-SQL and CLR types for return value do not match.
当前执行的函数创建SQL命令:
CREATE FUNCTION [dbo].[CleanFile](@filename nvarchar(500), @runmode int) RETURNS nvarchar(500) WITH EXECUTE AS CALLER AS EXTERNAL NAME [sqlFileClean].[sqlFileClean].[CleanFile]
对应的C# DLL代码片段:
//usings removed for visibility public class sqlFileClean { [Microsoft.SqlServer.Server.SqlFunction] public static SqlString CleanFile( SqlString FileName, SqlInt32 RunMode) { try { //Code removed here for visibility } catch (Exception ex) { // return any unhandled error message return ex.Message; } } };
排查思路(按优先级从高到低)
- 第一优先级检查所有返回分支的类型:你贴出的代码里catch块直接返回
ex.Message,这是普通C#string类型,不是方法声明的SqlString类型。SqlString和普通string不存在隐式转换,只要方法内任意一个返回分支的类型和声明的返回类型不一致,就会触发这个报错。这里需要改成return new SqlString(ex.Message);,同时还要检查try块内的所有返回值,确保都是SqlString类型,不能直接返回普通string、null或者其他类型值。 - 核对DLL编译目标平台与SQL Server实例位数:如果SQL Server是64位实例,DLL编译时选了x86目标平台,或是32位实例加载了x64专属编译的DLL,会触发类型加载异常,这类异常很多时候会被误报为返回类型不匹配。编译时目标平台优先选
AnyCPU,不要勾选“首选32位”选项。 - 确认SQL Server中加载的是最新编译的DLL:不少开发者改完代码重新编译后,没有在SQL Server中执行
ALTER ASSEMBLY更新程序集,或是更新时选错了旧版本DLL的路径,导致数据库中存储的还是旧版本代码。可以执行以下语句确认当前加载的程序集更新时间:SELECT name, clr_name, create_date, modify_date FROM sys.assemblies WHERE name = 'sqlFileClean' - 检查
SqlFunction特性配置:确认没有给特性手动配置错误的返回类型相关参数,无特殊逻辑的SqlString返回不需要额外加特性配置。 - 核对项目引用的SQL Server类型库版本:如果引用的
Microsoft.SqlServer.Types库版本高于当前SQL Server实例版本,可能出现类型映射识别错误,替换为和实例版本一致的引用即可。 - 确认EXTERNAL NAME路径完全匹配:检查C#代码里的
sqlFileClean类是否在根命名空间下,没有嵌套在其他命名空间中,路径写法错误加载到其他方法时也可能报类型不匹配。可以执行以下SQL查询已加载程序集包含的所有类和方法签名,逐一核对:SELECT asm.name AS assembly_name, clr.name AS class_name, clr.method_name FROM sys.assembly_modules clr JOIN sys.assemblies asm ON clr.assembly_id = asm.assembly_id - 做最小化验证定位问题:把try块内的业务代码全部注释,直接在方法第一行写
return new SqlString("test");,重新编译更新程序集后再尝试创建函数,如果能创建成功,就可以确定是原有业务代码中的返回分支存在问题。
内容的提问来源于stack exchange,提问作者JBird
相关产品推荐
相关产品推荐

