.NET Core中C#调用含自定义表类型参数的存储过程出现类型冲突错误的原因排查
问题原因与解决方案
这个错误的根源其实是参数匹配顺序的问题,咱们一步步拆解来看:
错误原因分析
你的存储过程[SP-Name]定义的参数顺序是:
CREATE PROCEDURE [SP-Name] ( @Id INT = 1, @UserName VARCHAR(500) = 'test', @Item1 Type1 READONLY, @Item2 Type2 READONLY )
前两个是普通类型的可选参数,第三、第四才是表类型参数。
而你调用时写的是:
ENTITIES.SqlQuery<Result>("EXEC [SP-Name] @Item1", ...)
这里没有显式指定参数名,SQL Server会严格按照存储过程定义的参数顺序来匹配传入的值——它会把你传的@Item1表类型参数,直接匹配到第一个参数@Id(int类型),这就直接触发了类型不兼容的错误:Operand type clash: Item1 is incompatible with int。
解决方案
有两种可靠的修复方式,推荐第一种:
1. 显式指定参数名(推荐)
在EXEC语句里明确指定参数名,让SQL Server直接匹配对应的参数,彻底避免顺序问题:
ENTITIES.SqlQuery<Result>( "EXEC [SP-Name] @Item1 = @Item1Param", new[] { new SqlParameter { SqlDbType = SqlDbType.Structured, TypeName = "Type1", Value = listItems.ToDataTable(), ParameterName = "Item1Param" } } ).ToList();
或者更简洁的写法(参数名可以和存储过程参数名一致):
ENTITIES.SqlQuery<Result>( "EXEC [SP-Name] @Item1 = @Item1", new[] { new SqlParameter { SqlDbType = SqlDbType.Structured, TypeName = "Type1", Value = listItems.ToDataTable(), ParameterName = "Item1" } } ).ToList();
2. 按顺序传入所有前置参数
如果你不想指定参数名,需要严格按照存储过程的参数顺序,先传入前两个可选参数(可以用DEFAULT关键字使用默认值):
ENTITIES.SqlQuery<Result>( "EXEC [SP-Name] DEFAULT, DEFAULT, @Item1", new[] { new SqlParameter { SqlDbType = SqlDbType.Structured, TypeName = "Type1", Value = listItems.ToDataTable(), ParameterName = "Item1" } } ).ToList();
DEFAULT表示使用存储过程定义的默认值(@Id=1、@UserName='test'),这样SQL Server就能正确把@Item1匹配到第三个参数位置。
额外注意点
你的Result类中Value属性定义为string类型,但存储过程返回的@Item1.Value是float类型,这可能会导致后续的类型转换警告或错误,建议把Result类的Value改成float或double类型:
public class Result { public int Id { get; set; } public float Value { get; set; } // 改为float类型 }
内容的提问来源于stack exchange,提问作者Mohamad Hasan Salmaaniyaan
相关产品推荐
相关产品推荐

