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

如何通过存储过程将DataTable与变量数据插入SQL目标表

解决ASP.NET Grid数据插入关联表的问题

你的思路已经很清晰了,核心就是把刚插入TBL_FAMILY_HEAD生成的family_head_id,和传入的表值类型typ_fam_mem里的每条数据结合,批量插入到tbl_family_member中。下面是完善后的存储过程实现:

完整的存储过程代码

CREATE PROCEDURE [dbo].[P_SET_PROFILE_REGISTRATION] 
(
    -- 家庭主表参数
    @P_NAME NVARCHAR(200),
    @P_GENDER TINYINT,
    -- 家庭成员表值类型参数
    @P_FAMILY_DT DBO.typ_fam_mem READONLY,
    -- 输出参数:1=成功,0=失败
    @V_OUT TINYINT OUTPUT
)
AS
DECLARE @FAMILY_HEAD_ID BIGINT;
BEGIN
    SET NOCOUNT ON;
    SET @V_OUT = 0; -- 默认设为失败状态

    BEGIN TRY
        -- 开启事务,确保两张表的操作原子性
        BEGIN TRANSACTION;

        -- 插入家庭主表并获取自增ID
        INSERT INTO [DBO].[TBL_FAMILY_HEAD] ([NAME], [GENDER])
        VALUES (@P_NAME, @P_GENDER);

        SET @FAMILY_HEAD_ID = SCOPE_IDENTITY();

        -- 批量插入家庭成员数据:把家庭主ID和表值类型数据关联
        IF @@ROWCOUNT > 0 AND EXISTS(SELECT 1 FROM @P_FAMILY_DT)
        BEGIN
            INSERT INTO [DBO].[tbl_family_member]
            (
                family_head_id,
                mem_name,
                mem_gender,
                mem_occupation,
                mem_maritial_status
            )
            SELECT 
                @FAMILY_HEAD_ID, -- 每个成员都关联同一个家庭主ID
                mem_name,
                mem_gender,
                mem_occupation,
                mem_maritial_status
            FROM @P_FAMILY_DT;
        END

        -- 提交事务
        COMMIT TRANSACTION;
        SET @V_OUT = 1; -- 操作成功,更新输出参数
    END TRY
    BEGIN CATCH
        -- 回滚事务,确保数据一致性
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
        
        -- 可扩展:添加错误日志记录,比如写入错误表
        -- INSERT INTO error_log (error_message, error_date) VALUES (ERROR_MESSAGE(), GETDATE());
        
        SET @V_OUT = 0; -- 操作失败
    END CATCH
END

关键要点解释

  • 事务处理:添加事务保证家庭主表和家庭成员表的操作原子性,避免出现只有家庭主数据但无成员数据的不一致情况。
  • 批量插入逻辑:用INSERT...SELECT替代循环插入,一次性关联@FAMILY_HEAD_ID和表值类型的所有数据,效率更高。
  • 空值判断:通过EXISTS判断表值参数是否有数据,避免无成员时执行无效插入。
  • 输出参数:默认设为失败状态,成功后更新为1,方便调用方快速判断操作结果。
  • 错误回滚:异常时回滚所有操作,保证数据完整性。

ASP.NET端调用提示(C#示例)

在ASP.NET中,只需把Grid数据转换成DataTable,再作为表值参数传入存储过程:

// 构建家庭成员DataTable
DataTable familyDt = new DataTable();
familyDt.Columns.Add("mem_name", typeof(string));
familyDt.Columns.Add("mem_gender", typeof(byte));
familyDt.Columns.Add("mem_occupation", typeof(string));
familyDt.Columns.Add("mem_maritial_status", typeof(byte));

// 从GridView行填充数据
foreach (GridViewRow row in GridView1.Rows)
{
    if (row.RowType == DataControlRowType.DataRow)
    {
        DataRow dr = familyDt.NewRow();
        dr["mem_name"] = ((TextBox)row.FindControl("txtName")).Text;
        dr["mem_gender"] = byte.Parse(((DropDownList)row.FindControl("ddlGender")).SelectedValue);
        // 填充其他字段
        familyDt.Rows.Add(dr);
    }
}

// 调用存储过程
using (SqlConnection conn = new SqlConnection(yourConnectionString))
{
    SqlCommand cmd = new SqlCommand("P_SET_PROFILE_REGISTRATION", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    
    // 添加家庭主表参数
    cmd.Parameters.AddWithValue("@P_NAME", txtHeadName.Text);
    cmd.Parameters.AddWithValue("@P_GENDER", byte.Parse(ddlHeadGender.SelectedValue));
    
    // 添加表值参数
    SqlParameter tvpParam = cmd.Parameters.AddWithValue("@P_FAMILY_DT", familyDt);
    tvpParam.SqlDbType = SqlDbType.Structured;
    tvpParam.TypeName = "dbo.typ_fam_mem";
    
    // 输出参数
    SqlParameter outParam = cmd.Parameters.Add("@V_OUT", SqlDbType.TinyInt);
    outParam.Direction = ParameterDirection.Output;
    
    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();
    
    // 处理结果
    byte result = (byte)outParam.Value;
    if (result == 1)
    {
        // 操作成功逻辑
        Response.Write("注册成功!");
    }
    else
    {
        // 操作失败逻辑
        Response.Write("注册失败,请重试!");
    }
}

内容的提问来源于stack exchange,提问作者user4221591

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:13:17