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

如何用同一SQL存储过程实现INSERT或UPDATE操作?

解决INSERT/UPDATE存储过程的DBNull输出参数问题

问题根源

你遇到的错误是因为UPDATE分支未对输出参数@id赋值:当执行UPDATE操作时,@id未被设置有效值,Dapper尝试读取该参数时得到DBNull,但C#中ticket.id是不可空的int类型,类型转换失败抛出异常。

解决方案1:完善分支逻辑,确保UPDATE分支赋值@id

直接在UPDATE块中添加语句,将现有工单的id赋值给输出参数:

ALTER PROCEDURE [dbo].[spTickets_InsertUpdate]
    @TicketNumber nchar(10),
    @StraightTime money,
    @OverTime money,
    @AdditionalPay money,
    @id int = 0 OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    IF EXISTS (SELECT 1 FROM Tickets WHERE TicketNumber = @TicketNumber)
    BEGIN
        UPDATE dbo.Tickets
        SET AdditionalPay = @AdditionalPay
        WHERE TicketNumber = @TicketNumber;
        
        -- 新增:获取现有工单的id赋值给输出参数
        SELECT @id = id FROM Tickets WHERE TicketNumber = @TicketNumber;
    END
    ELSE
    BEGIN
        INSERT INTO dbo.Tickets (TicketNumber, StraightTime, OverTime, AdditionalPay)
        VALUES (@TicketNumber, @StraightTime, @OverTime, @AdditionalPay);

        SELECT @id = SCOPE_IDENTITY();
    END
END

这样无论执行INSERT还是UPDATE,@id都会被赋值,Dapper读取时不会遇到DBNull,类型转换正常。

解决方案2:使用MERGE语句简化逻辑(推荐)

MERGE语句可一次性完成判断、插入和更新操作,通过OUTPUT子句统一获取id,逻辑更简洁且避免分支遗漏:

ALTER PROCEDURE [dbo].[spTickets_InsertUpdate]
    @TicketNumber nchar(10),
    @StraightTime money,
    @OverTime money,
    @AdditionalPay money,
    @id int = 0 OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    MERGE INTO dbo.Tickets AS Target
    USING (VALUES (@TicketNumber, @StraightTime, @OverTime, @AdditionalPay)) 
        AS Source (TicketNumber, StraightTime, OverTime, AdditionalPay)
    ON Target.TicketNumber = Source.TicketNumber
    WHEN MATCHED THEN
        UPDATE SET Target.AdditionalPay = Source.AdditionalPay
    WHEN NOT MATCHED THEN
        INSERT (TicketNumber, StraightTime, OverTime, AdditionalPay)
        VALUES (Source.TicketNumber, Source.StraightTime, Source.OverTime, Source.AdditionalPay)
    OUTPUT inserted.id INTO @id; -- 统一获取插入或更新后的id
END

额外优化建议

为避免重复工单,建议给TicketNumber添加唯一约束:

ALTER TABLE dbo.Tickets ADD CONSTRAINT UQ_Tickets_TicketNumber UNIQUE (TicketNumber);

C#代码无需修改

现有C#代码可直接调用修改后的存储过程,@id参数始终会被赋值,Dapper能正常将其转换为int类型赋值给ticket.id。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 11:20:32