SQL Server逐行传递表值参数:C#与遗留存储过程适配问题
表值参数存储过程调用单行遗留存储过程的实现方案
看起来你需要搭建一个“中间层”存储过程,它接收表类型参数,然后逐行把数据转发给那个只接受单个字段参数的遗留存储过程。结合你给出的C#类和表值类型需求,我给你整理了完整的实现步骤:
1. 补全SQL表值类型定义
首先把你的表值类型补全,要和C#的CondemnedPart类字段一一对应:
CREATE TYPE dbo.CondemnedPartType AS TABLE ( HarvestDate DATETIME, HouseTag2 VARCHAR(100), -- 长度可根据实际业务调整 Reason TINYINT, Product TINYINT ) GO
2. 编写接收表值参数的主存储过程
这个存储过程会遍历传入的表数据,逐行调用遗留存储过程。这里用游标来处理逐行操作(中小数据量场景下足够好用;如果数据量极大,可考虑结合自增ID的WHILE循环,但遗留存储过程只接受单行参数,逐行调用是必然选择):
CREATE PROCEDURE dbo.ProcessCondemnedParts @CondemnedParts CondemnedPartType READONLY AS BEGIN SET NOCOUNT ON; -- 声明游标遍历表参数 DECLARE @cursor CURSOR; DECLARE @HarvestDate DATETIME, @HouseTag2 VARCHAR(100), @Reason TINYINT, @Product TINYINT; SET @cursor = CURSOR FOR SELECT HarvestDate, HouseTag2, Reason, Product FROM @CondemnedParts; OPEN @cursor; FETCH NEXT FROM @cursor INTO @HarvestDate, @HouseTag2, @Reason, @Product; WHILE @@FETCH_STATUS = 0 BEGIN -- 替换成你的遗留存储过程名称和参数顺序 EXEC dbo.LegacyCondemnedPartProcedure @HarvestDate = @HarvestDate, @HouseTag2 = @HouseTag2, @Reason = @Reason, @Product = @Product; FETCH NEXT FROM @cursor INTO @HarvestDate, @HouseTag2, @Reason, @Product; END CLOSE @cursor; DEALLOCATE @cursor; END GO
3. C#端代码示例
把CondemnedPart列表转换成DataTable,然后传入主存储过程:
using System.Data; using System.Data.SqlClient; using System.Collections.Generic; public class CondemnedPartService { public void ProcessParts(List<CondemnedPart> condemnedParts) { // 替换为你的数据库连接字符串 string connectionString = "YourConnectionStringHere"; using (SqlConnection conn = new SqlConnection(connectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("dbo.ProcessCondemnedParts", conn)) { cmd.CommandType = CommandType.StoredProcedure; // 将实体列表转换为DataTable DataTable partTable = ConvertToDataTable(condemnedParts); // 创建表值参数 SqlParameter tvpParam = cmd.Parameters.AddWithValue("@CondemnedParts", partTable); tvpParam.SqlDbType = SqlDbType.Structured; tvpParam.TypeName = "dbo.CondemnedPartType"; // 需与SQL端类型名完全一致 cmd.ExecuteNonQuery(); } } } // 辅助方法:将实体列表转为DataTable private DataTable ConvertToDataTable(List<CondemnedPart> parts) { DataTable table = new DataTable(); table.Columns.Add("HarvestDate", typeof(DateTime)); table.Columns.Add("HouseTag2", typeof(string)); table.Columns.Add("Reason", typeof(byte)); table.Columns.Add("Product", typeof(byte)); foreach (var part in parts) { table.Rows.Add(part.HarvestDate, part.HouseTag2, part.Reason, part.Product); } return table; } } // 你的实体类 public class CondemnedPart { public DateTime HarvestDate { get; set; } public string HouseTag2 { get; set; } public byte Reason { get; set; } public byte Product { get; set; } }
关键注意事项
- 确保SQL表值类型的字段类型、顺序与C#实体类完全匹配,否则会触发参数不匹配错误。
- 如果遗留存储过程有返回值或输出参数,可在主存储过程的循环中捕获并处理。
- 生产环境中建议添加异常处理:C#端用
try-catch块,SQL端用TRY-CATCH块捕获执行异常。
内容的提问来源于stack exchange,提问作者rigamonk
相关产品推荐
相关产品推荐

