在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
相关产品推荐
相关产品推荐

