2017-10-09 56 views
4

我有一个存储过程,在这里我做一个INSERT,然后在这种情况下,一个RAISERROR("MyException", 5, 5)插入失败。SQL Server存储过程抛出多重错误

的问题是,结果到我的.NET应用程序是

MyException:不能将NULL值...

所以它返回一个2个例外。

我的.NET代码总是将整个字符串与“MyException”匹配,但不再工作。

这是标准吗?如果是这样,这怎么可能以前工作?有没有任何设置?

编辑:

使用.NET表格适配器来处理SQL数据库。

版本

产品:Microsoft SQL Server的企业单位(64位) 版本:11.0.2100.60 集群:假 HADR:假

微软.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错误,它可能会失败。

+1

请问您可以提供有关sql-server版本和.net版本的信息吗?什么结构os存储过程?交易? try/catch – MtwStark

+0

*我的.NET代码总是将整个字符串与“MyException”匹配,但是... *您可以共享执行此操作的代码吗? –

+0

为了使RAISERROR引发异常,指定的严重性必须为11或更大。试试'RAISERROR('MyException',16,5)'。请注意,单引号允许您使用'QUOTED_IDENTIFIER ON'运行,这是最佳做法。 –

回答

10

批处理执行期间发生的严重级别为11或更高的错误将在SqlClient API引发异常时作为SqlException返回给应用程序。单个错误返回SqlException.Errors集合中,SqlException.Message包含集合中各个错误的连接文本。

某些SQL Server错误将终止该批处理,因此错误发生后批处理中没有后续语句执行。在这种情况下,只返回在批终止错误之前发生的错误。所有错误将在多个错误发生时返回并且没有批处理终止。所以,根据具体的错误,后续的RAISERROR可能不会被执行。

请记住,默认行为是SQL Server将继续在内部和外部过程中不发生批处理终止错误(包括严重性为16的RAISERROR)的T-SQL语句。这可能会导致多个错误回。

通常人们不想在错误发生后继续执行批处理并引发单个错误。这可以通过一个或多个以下方法来避免:

  • 使用结构化的错误处理(try/catch语句),并控制沿每个语句后使用的THROW代替RAISERROR

  • 检查@@ ERROR流语句

  • 指定设定XACT_ABORT_ON使非批量终止错误都提升到批量终止错误和事务回滚

SET XACT_ABORT_ON是带有explict事务的存储过程中的最佳实践,以确保事务在客户端超时或查询取消时回滚。该批次也将被终止,除非TRY/CATCH块在范围内。

在你的情况,我建议你添加一个TRY/CATCH块到外部proc。 CATCH块将在内部或外部过程中出现错误后执行。 CATCH块代码然后可以使用THROW(SQL Server 2012及更高版本)或用户定义的错误012xx严重性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 
+0

有关更多详细信息,请参阅[MS Docs RAISERROR](https://docs.microsoft.com/zh-cn/sql/t-sql/language-elements/raiserror-transact-sql)中的注释部分。另外请注意,引入了“新应用程序应该使用[THROW](https://docs.microsoft.com/en-us/sql/t-sql/language-elements/throw-transact-sql)”的相同链接“。 – SMM

+0

执行up_kod_save并且此SP中的逻辑将导致RAISERROR('MyApp_EXCEPTION_UPPDATERAD_AV_ANNAN',16,1)。奇怪的是,这只会把你从up_kod_save而不是up_kod_text_save中抛出。 up_kod_text_save将继续执行,就像没有错误被抛出一样。如果结果为null,则kod_id也将为空,并且在插入时会导致新的SQL异常。在这一点上,我们将被抛出up_kod_text_save,但有更多的例外? – Banshee

+0

这一直在工作(只有一个例外返回),所以我们不知道为什么这种行为已经改变。也许有些更新? – Banshee