2017-10-09 55 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