C#向SQL Server存储过程传递DataSet参数失败排查
嘿,我帮你排查下问题——你已经摸到了门道(设置SqlDbType.Structured),但还有几个关键细节没做好,导致SQL Server没接收到你的表值参数:
你传的是
DataSet,但表值参数需要的是DataTable
SQL Server的表值参数(TVP)只认单个数据表(DataTable)、DbDataReader或者IEnumerable<SqlDataRecord>,DataSet是多表容器,SQL Server不知道该取哪个表来映射参数,自然就忽略了。自定义表类型和传入的DataTable结构不匹配
你的SQL自定义表类型是CREATE TYPE dbo.MyTable AS TABLE(BatchID INT);,但你的DataTable列名是ID,而且存储过程里写的是SELECT ID FROM @MyTableParam——列名完全对不上,SQL Server没法把DataTable的数据映射到TVP里,等于传了个空表。调用存储过程时没指定
CommandType.StoredProcedure
如果你的ExecuteNonQuery方法默认把第一个参数当成SQL语句而非存储过程名,那数据库会把"dbo.MySproc"当成普通SQL执行,根本不会触发存储过程,参数自然就没被传递。
C# 代码
if (tblNoMatch.Rows.Count > 0) { // 从DataSet里取出你要传递的具体DataTable(这里假设是第一个表) DataTable targetTable = tblNoMatch.Tables[0]; var tblParameter = new SqlParameter { ParameterName = "@MyTableParam", SqlDbType = SqlDbType.Structured, // 显式指定自定义表类型的名称,帮SQL Server精准识别 TypeName = "dbo.MyTable", // 传DataTable,不是DataSet! Value = targetTable }; // 注意两点:指定CommandType为存储过程,@IsProcessed传int而非字符串 pge.dbconn.ExecuteNonQuery( "dbo.MySproc", CommandType.StoredProcedure, tblParameter, new SqlParameter("@IsProcessed", 2) ); pge.dbconn.ShutDown(); }
补充:
@IsProcessed的SQL类型是smallint,直接传整数2比字符串"2"更稳妥,避免不必要的类型转换错误。
SQL 存储过程修正
要么调整自定义表类型的列名和DataTable一致:
IF TYPE_ID(N'MyTable') IS NULL CREATE TYPE dbo.MyTable AS TABLE(ID INT); GO ALTER PROCEDURE [dbo].[MySproc] @MyTableParam AS dbo.MyTable READONLY, @IsProcessed [smallint] = 0 AS IF (SELECT COUNT(*) FROM @MyTableParam) > 0 BEGIN UPDATE [dbo].[MyTable] SET [IsProcessed] = ISNULL(@IsProcessed, IsProcessed) WHERE [ID] IN (SELECT ID FROM @MyTableParam) END
要么保持自定义表类型的BatchID,但修改存储过程的查询逻辑,同时把DataTable的列名改成BatchID:
ALTER PROCEDURE [dbo].[MySproc] @MyTableParam AS dbo.MyTable READONLY, @IsProcessed [smallint] = 0 AS IF (SELECT COUNT(*) FROM @MyTableParam) > 0 BEGIN UPDATE [dbo].[MyTable] SET [IsProcessed] = ISNULL(@IsProcessed, IsProcessed) -- 这里要和自定义表类型的列名一致 WHERE [ID] IN (SELECT BatchID FROM @MyTableParam) END
改完之后用SQL Server Profiler再跟踪一次,你应该能看到@MyTableParam被正确传递,并且存储过程里的计数查询能返回40条数据了。
内容的提问来源于stack exchange,提问作者Kevin Henzel

