You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#向SQL Server存储过程传递DataSet参数失败排查

嘿,我帮你排查下问题——你已经摸到了门道(设置SqlDbType.Structured),但还有几个关键细节没做好,导致SQL Server没接收到你的表值参数:

核心问题分析
  1. 你传的是DataSet,但表值参数需要的是DataTable
    SQL Server的表值参数(TVP)只认单个数据表(DataTable)、DbDataReader或者IEnumerable<SqlDataRecord>,DataSet是多表容器,SQL Server不知道该取哪个表来映射参数,自然就忽略了。

  2. 自定义表类型和传入的DataTable结构不匹配
    你的SQL自定义表类型是CREATE TYPE dbo.MyTable AS TABLE(BatchID INT);,但你的DataTable列名是ID,而且存储过程里写的是SELECT ID FROM @MyTableParam——列名完全对不上,SQL Server没法把DataTable的数据映射到TVP里,等于传了个空表。

  3. 调用存储过程时没指定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:41:49