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

在C# WinForm中使用ExecuteScalar捕获SQL Server存储过程Try/Catch中的错误

解决方案

问题原因

当存储过程通过TRY/CATCH捕获错误并使用RAISERROR抛出时,ExecuteScalar()会优先尝试获取第一个结果集的第一行第一列值。由于错误触发后select 10未执行,存储过程没有返回预期的结果集,ExecuteScalar()返回null,同时SQL Server发送的错误消息没有被客户端的异常捕获逻辑正确处理。而ExecuteNonQuery()不关注结果集,能直接捕获到错误。

方案1:使用THROW替代RAISERROR(推荐,SQL Server 2012+)

THROW会将错误以原生异常形式传递给客户端,能被ExecuteScalar()的SqlException捕获,同时支持保留原始错误信息。修改存储过程如下:

BEGIN
BEGIN TRY
    SELECT 1/0
    SELECT 10
END TRY
BEGIN CATCH
    -- 自定义错误:错误号需大于50000,消息和级别按需设置
    THROW 50000, 'Some Error Message', 1;
    -- 若要抛出原始错误,直接用不带参数的THROW
    -- THROW;
END CATCH
END

C#端代码无需大幅修改,保持ExecuteScalar()调用并捕获SqlException即可:

try
{
    var result = cmd.ExecuteScalar();
    if (result != null)
    {
        int returnID = (int)result;
        // 处理返回的ID
    }
}
catch (SqlException ex)
{
    // 展示错误消息:ex.Message
}

方案2:改用OUTPUT参数返回ID,搭配ExecuteNonQuery()

如果需要兼容低版本SQL Server,可通过OUTPUT参数传递返回的ID,用ExecuteNonQuery()执行存储过程,既能获取ID又能正常捕获错误:

存储过程修改:

CREATE PROCEDURE GetReturnID
    @ReturnID INT OUTPUT
AS
BEGIN
BEGIN TRY
    -- 模拟业务逻辑,此处替换为实际获取ID的代码
    SELECT 1/0;
    SET @ReturnID = 10;
END TRY
BEGIN CATCH
    RAISERROR('Some Error Message', 16, 1);
END CATCH
END

C#端代码:

using (SqlConnection conn = new SqlConnection("你的连接字符串"))
{
    conn.Open();
    SqlCommand cmd = new SqlCommand("GetReturnID", conn);
    cmd.CommandType = CommandType.StoredProcedure;

    // 添加OUTPUT参数
    SqlParameter outputParam = new SqlParameter("@ReturnID", SqlDbType.Int);
    outputParam.Direction = ParameterDirection.Output;
    cmd.Parameters.Add(outputParam);

    try
    {
        cmd.ExecuteNonQuery();
        int returnID = (int)outputParam.Value;
        // 处理返回的ID
    }
    catch (SqlException ex)
    {
        // 展示错误消息
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:18:26