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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:18:09