我有一个存储过程,我执行INSERT
,然后RAISERROR("MyException", 5, 5)
,在这种情况下,插入失败。
问题是我的.NET应用程序的结果是
MyException:无法插入值NULL ...
所以它在一个中返回2个例外。
我的.NET代码总是将整个字符串与" MyException"匹配。但那不再适用了。
这是标准吗?如果是这样,那之前怎么可能有效呢?有什么设置吗?
编辑:
我使用.NET表适配器来处理SQL数据库。
版本
产品:Microsoft SQL Server Enterprice(64位) 版本:11.0.2100.60 集群:错误 HADR:错误
Microsoft Framework .NET 4.6.2
存储过程
ALTER Procedure [dbo].[up_kod_text_save]
-- Add the parameters for the stored procedure here
@entity_id int,
@text varchar(300),
@kod_key int,
@kod_id int,
@korttext varchar(10),
@inaktiv bit,
@primar_extern_kod varchar(300),
@sparad_av varchar(128),
@kod_typ_id int,
@kod varchar(20),
@original_rowver rowversion,
@associerat_varde decimal(18,5),
@beskrivning varchar(2000),
@viktigt_varde bit
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @resultat table(kod_id int, uppdat_tidpunkt datetime, rowver binary(8) );
Insert into @resultat
exec up_kod_save @kod_id,@text,@korttext,@inaktiv,@primar_extern_kod,@sparad_av,@kod_typ_id,@kod,@original_rowver, @associerat_varde, @beskrivning,@viktigt_varde
declare @uppdat_tidpunkt datetime
declare @rowver rowversion
declare @tablename varchar(30)
declare @idname varchar(30)
SET @rowver = (SELECT rowver FROM @resultat)
SET @kod_id = (SELECT kod_id from @resultat)
------------------------------------------------------------------------------------
set @uppdat_tidpunkt = getdate()
IF(@kod_key = 2)
BEGIN
ELSE IF(@kod_key = 11)
BEGIN
IF EXISTS ( SELECT akut_checklista_id FROM akut_checklista WHERE akut_checklista_id = @entity_id )
BEGIN
UPDATE akut_checklista
SET [text] = @text,
[kod_id] = @kod_id
WHERE akut_checklista_id = @entity_id
END
ELSE
BEGIN
-- Skapa master-rad
INSERT INTO [akut_checklista] ([text], [kod_id])
VALUES (@text, @kod_id);
set @entity_id = SCOPE_IDENTITY()
END
END
ELSE
BEGIN
RAISERROR ('MyApp_EXCEPTION_UPPDATERAD_AV_ANNAN',16,1)
RETURN
END
SELECT @entity_id as entity_id, @rowver as rowver, @kod_id as kod_id, @uppdat_tidpunkt as uppdat_tidpunkt
up_kod_save只更新\插入而没有任何事务。但是,如果rowversion错误,它可能会失败。
答案 0 :(得分:10)
当SqlException
API引发异常时,批处理执行期间严重性为11或更高的错误将作为SqlClient
返回给应用程序。个人错误在SqlException.Errors
集合中返回,SqlException.Message
包含集合中各个错误的连接文本。
某些SQL Server错误将终止批处理,因此错误后不会执行批处理中的后续语句。在这种情况下,仅返回批处理终止错误之前发生的错误。发生多个错误且没有批处理终止时,将返回所有错误。因此,根据具体错误,可能不会执行后续RAISERROR
。
请记住,默认行为是SQL Server将继续在内部和外部过程中执行T-SQL语句,不会发生批处理终止错误,包括严重级为16的RAISERROR
。这可能会导致在多个错误返回。
通常,一个人不想在错误后继续批量执行并引发一个错误。这可以通过以下一种或多种技术来避免:
使用结构化错误处理(TRY / CATCH)并使用THROW
代替RAISERROR
在每个语句之后检查@@ ERROR以及控制流语句
指定SET XACT_ABORT_ON,以便将非批处理终止错误提升为批处理终止错误并回滚事务
SET XACT_ABORT_ON
是存储过程中带有明确事务的最佳实践,可确保在客户端超时或查询取消时回滚事务。除非TRY / CATCH块在范围内,否则批次也将被终止。
在你的情况下,我建议你在外部proc中添加一个TRY / CATCH块。在内部或外部proc中发生错误后,将执行CATCH
块。然后,CATCH
块代码可以使用THROW
(SQL Server 2012及更高版本)或RAISERROR
严重性为11+的用户定义错误引发原始错误,以在客户端应用程序中引发异常。以下是一个例子。
CREATE PROCEDURE [dbo].[up_kod_text_save]
-- parameters here
AS
SET NOCOUNT ON;
BEGIN TRY
-- code here
END TRY
BEGIN CATCH --catch block will be entered after an error in either proc
IF @@TRANCOUNT > 0 ROLLBACK; --needed only if BEGIN TRAN is used
THROW; --this will raise the original error
END;
GO