Fab*_*iro 8 c# sql asp.net exception-handling sql-server-2008
我在存储过程中使用TRY CATCH块,其中有两个INSERT指令.
如果出现问题,CATCH块会负责回滚所做的所有更改并且工作正常,除了一件事!
我的ASP.NET应用程序捕获的异常是一个数字为50000的SqlException.这不是原始数字!(我期待的数字是2627)
在异常的Message属性中,我可以看到原始的异常编号和格式化的消息.
我怎样才能获得原始的例外号码?
try
{
// ... code
}
catch
(SqlException sqlException)
{
switch (sqlException.Number)
{
// Name already exists
case 2627:
throw new ItemTypeNameAlreadyExistsException();
// Some other error
// As the exception number is 50000 it always ends here!!!!!!
default:
throw new ItemTypeException();
}
}
Run Code Online (Sandbox Code Playgroud)
现在,返回值已被使用.我想我可以使用输出参数来获取异常编号,但这是个好主意吗?
我该怎么做才能获得例外号码?谢谢
PS:这是必需的,因为我有两个INSERT指令.
gbn*_*gbn 12
您可以像这样重新抛出它:
..
END TRY
BEGIN CATCH
DECLARE @errnum int;
SELECT @errnum = ERROR_NUMBER();
RAISERROR (@errnum, 16, 1);
END CATCH
Run Code Online (Sandbox Code Playgroud)
但是,由于ERROR_NUMBER()的sys.messages行中的%s等占位符,您很可能会失去意义.
你可以做这样的事情来包括数字并重新抛出原始信息
..
END TRY
BEGIN CATCH
DECLARE @errnum nchar(5), @errmsg nvarchar(2048);
SELECT
@errnum = RIGHT('00000' + ERROR_NUMBER(), 5),
@errmsg = @errnum + ' ' + ERROR_MESSAGE();
RAISERROR (@errmsg, 16, 1);
END CATCH
Run Code Online (Sandbox Code Playgroud)
前5个字符是原始数字.
但是如果你有嵌套代码,那么你最终会得到"00123 00456错误文本".
就个人而言,我只处理SQL异常数字以将我的错误(50000)与我的代码未运行的引擎错误(例如缺少参数)分开.
最后,您可以将其传递给返回值.
我问了一个问题:SQL Server错误处理:异常和数据库 - 客户端契约
如果在T-SQL中使用BEGIN TRY/BEGIN CATCH,则会丢失原始引擎引发的异常.您不应该手动引发系统错误,因此您无法重新引发原始错误号2627.T-SQL错误处理与C#/ C++错误处理不相似,没有办法重新抛出原始错误例外.存在这种限制的原因有很多,但足以说明这一点存在,你不能忽视它.
但是,只要它们高于50000范围,提出自己的错误代码就没有限制.安装应用程序时,使用sp_addmessage注册自己的消息:
exec sp_addmessage 50001, 16, N'A primary key constraint failed: %s';
Run Code Online (Sandbox Code Playgroud)
在你的T-SQL中你会引发新的错误:
@error_message = ERROR_MESSAGE();
raiserror(50001, 16, 1, @error_message;
Run Code Online (Sandbox Code Playgroud)
在C#代码中,您将查找错误号50001而不是2627:
foreach(SqlError error in sqlException.Errors)
{
switch (error.Number)
{
case 50001:
// handle PK violation
case 50002:
//
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个更简单的答案,但遗憾的是这就是事情的方式.T-SQL异常处理没有将seamlesly集成到CLR异常处理中.
谢谢你们的回答。从重新引发的异常消息中获取错误是我已经做过的事情。
@gbn 我也喜欢 gbn 答案,但我会坚持这个答案,因为它是最有效的答案,我将其发布在这里希望它对其他人也有用。
答案是在应用程序中使用事务。如果我没有捕获存储过程中的异常,我将获得 SqlException 对象中的原始编号。在捕获应用程序中的原始异常后,我编写以下代码
transaction.Rollback();
Run Code Online (Sandbox Code Playgroud)
否则:
transaction.Commit();
Run Code Online (Sandbox Code Playgroud)
这比我最初预期的要简单得多!
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.aspx