使用C#和MS SQL用户定义表类型批量插入数据失败求助
问题分析与解决方案
你遇到的问题是:通过C#代码使用表值参数(TVP)调用SQL Server存储过程批量插入数据时无效果,但手动执行SQL脚本正常。以下是核心排查点和修正方案:
核心问题点
- 数据库连接未显式打开:Dapper虽支持隐式打开连接,但部分场景下会导致执行异常或无响应;
- 参数传递未指定名称:直接传递表值参数时,未与存储过程的
@ItemValues参数名绑定,导致存储过程无法识别输入; - 错误的Dapper方法选择:使用
Query<bool>查询方法执行非查询操作,存储过程无返回结果时会返回默认值false,无法判断执行状态; - 存储过程异常被吞:CATCH块仅回滚事务未抛出错误,导致C#代码无法感知插入失败的原因。
修正后的代码示例
C#代码(MVC环境)
try { var dataTable = new DataTable(); dataTable.Columns.Add("Name", typeof(string)); dataTable.Columns.Add("City", typeof(string)); dataTable.Columns.Add("Age", typeof(string)); dataTable.Rows.Add("ABC", "Mumbai", "24"); dataTable.Rows.Add("DEF", "Nasik", "30"); dataTable.Rows.Add("GHI", "Ahmedabad", "26"); var tvpParameter = dataTable.AsTableValuedParameter("dbo.typList"); using(var con = new SqlConnection(GetConnectionString())) { con.Open(); // 显式打开连接,避免隐式连接的不确定性 // 使用Execute执行非查询操作,明确绑定参数名 int affectedRows = con.Execute( "Usp_BulkInsert", new { ItemValues = tvpParameter }, // 参数名与存储过程一致 commandType: CommandType.StoredProcedure, commandTimeout: 1000 ); // 通过受影响行数验证插入结果 if(affectedRows > 0) { // 插入成功逻辑 } } } catch(Exception ex) { // 捕获并处理异常,排查失败原因 // 可写入日志或返回错误信息到前端 }
修正后的SQL存储过程
CREATE PROC [dbo].[Usp_BulkInsert] @ItemValues typList READONLY AS BEGIN BEGIN TRY BEGIN TRANSACTION; INSERT INTO EmployeeDetails (Name, City, Age) SELECT Name, City, Age FROM @ItemValues; COMMIT TRANSACTION; -- 返回受影响行数,供C#代码验证 SELECT @@ROWCOUNT AS AffectedRows; END TRY BEGIN CATCH IF (@@Trancount > 0) ROLLBACK TRANSACTION; -- 抛出异常,让C#代码能捕获到错误详情 THROW; END CATCH; END;
额外排查建议
- 确认
EmployeeDetails表的字段约束(如非空、长度限制)是否与输入数据匹配; - 检查数据库连接字符串是否正确指向目标数据库;
- 可在SQL Server Profiler中跟踪C#代码发起的存储过程调用,查看参数传递是否正确。
内容的提问来源于stack exchange,提问作者Shablu Rizvi
相关产品推荐
相关产品推荐

