2014-01-13 30 views
1

我想在插入選擇語句 的末尾調用存儲過程,但在事務的提交或回滾之前,我想存儲proc是包含插入選擇的事務的一部分。如果我希望新代碼成爲包含事務的一部分,是否只寫動態SQL是唯一的選擇?在包含動態sql的事務中嵌入對存儲過程的調用

字符串附加數量實際上相當大(數千),但我 只共享代碼的小片段,以突出顯示 的概念,並顯示我想要做什麼。

sqlStr.Append("BEGIN TRANSACTION; ") 

       sqlStr.Append("INSERT INTO table_chg (Column1, Column2) ")            
       sqlStr.Append("SELECT r.Column8 , r.Column9 ") 
       sqlStr.Append("FROM v_table r, table1 r ") 
       sqlStr.Append("WHERE r.columnName1 = '{1}' ") 
       sqlStr.Append(" AND r.coulumnName2 = '{2}'; ") 
       sqlStr.Append(" ") 


        /** ADD STORED PROCEDURE HERE */ 

        EXEC sp_storedProc '{1}' **THIS DOES NOT WORK. BUT {1} does resolve to the correct variable that I need. Also the stored procedure works standalone and the VB.Net code does try to reference the stored proc because if i give the stored proc an incorrect name i get an error back which says stored procedure not found** 

       sqlStr.Append("IF @@ERROR <> 0 ") 
       sqlStr.Append(" ROLLBACK TRANSACTION ") 
       sqlStr.Append("ELSE ") 
       sqlStr.Append(" COMMIT TRANSACTION; ") 



strError = DatabaseClass.ExecuteNonQueryReturnError 
(String.Format(sqlStr.ToString(), parameter1, parameter2)) 
+0

關於可行性的任何想法? – User1

+1

我假定這是您爲生成示例所做的簡化的副產品,但是您爲'v_table'和'table1'使用了別名'r'。這會導致錯誤。 –

+0

是的,這是正確的。這實際上是一個巨大的SQL語句,我砍下了.....好的觀察... – User1

回答

0

以下是你需要做的:

1 - 創建事務對象並使用Try-block

2 - 使用您的交易對象,執行SqlCommand.ExecuteNonQuery(插入) - 它會返回的記錄數影響。

3 - 使用您的交易對象,執行SqlCommand.ExecuteNonQuery(已過程) - 它將返回受影響的記錄數和[如果需要]輸出參數。

4 - 回滾或基於步驟#2的結果ANS提交您的交易對象#3

5 - 不這樣做

sqlStr.Append("INSERT INTO table_chg (Column1, Column2) ")            
sqlStr.Append("SELECT r.Column8 , r.Column9 ")..... 

而是做到這一點:

Dim sql as String = _ 
    "INSERT INTO table_chg (Column1, Column2) " & _ 
    "SELECT r.Column8 , r.Column9 "....... 
+0

你能解釋你對#5的推理嗎?儘管原始海報並未這麼說,但看起來他或她正在使用「StringBuilder」。使用連接字符串的好處是什麼? –

+0

當處理循環時,字符串生成器是絕對必須的。但是,當事先知道該字符串時,最好聲明一個字符串。字符串生成器需要資源。如果你沒有初始化它,它會在你添加數據時調整自己的大小,這將需要更多的資源。在目前情況下,使用'string'更合適。字符串是字節數組,字符串生成器是管理它的機制。這裏我們不需要它。 –

+0

你是對的。我們不應該使用字符串生成器。但不幸的是,我堅持這個代碼庫,而這個代碼所做的一切就是使用Sql代碼進行Stringbuilding ..... – User1

1

1)@@ ERROR一旦錯誤發生後執行任何其他語句,函數就會被重置爲空,所以最好在發生錯誤的地方使用變量。

2)在您的連接條件中,您對這兩個表使用了相同的別名r,這會導致錯誤。別名應該不同。在

3)使用ON條款加入

您@@ ERROR函數聲明應該是這個樣子

@@ ERROR

BEGIN TRANSACTION 
DECLARE @Error INT; 

    INSERT INTO table_chg (Column1, Column2)            
    SELECT r.Column8 , r.Column9 
    FROM v_table r1 INNER JOIN table1 r2   --<-- Alias should be different for 
    ON r1.ReferencingColumn = r2.ReferencingColumn  -- for both tables 
    WHERE r1.columnName1 = 1   --<-- Use r1 or r2 alias here 
    AND r2.coulumnName2 = 2 

    SET @Error = @@ERROR; 

IF (@Error <> 0) 
    ROLLBACK TRANSACTION 
ELSE 
    COMMIT TRANSACTION 

在try..catch區塊

我建議你使用try catch塊,就像這樣,它允許你在catch塊中使用錯誤函數並訪問有關錯誤的詳細信息。

BEGIN TRY 

    BEGIN TRANSACTION 
    DECLARE @Error INT; 

     INSERT INTO table_chg (Column1, Column2)            
     SELECT r.Column8 , r.Column9 
     FROM v_table r1 INNER JOIN table1 r2   --<-- Alias should be different for 
     ON r1.ReferencingColumn = r2.ReferencingColumn  -- for both tables 
     WHERE r1.columnName1 = 1   --<-- Use r1 or r2 alias here 
     AND r2.coulumnName2 = 2 

    COMMIT TRANSACTION 

END TRY 

BEGIN CATCH 
IF (@@TRANCOUNT > 0) 
    ROLLBACK TRANSACTION 

     SELECT ERROR_NUMBER() AS ERRORNUMBER, 
      ERROR_MESSAGE() AS ERRORMESSAGE 
      . 
      ...... (All the other error functions) 
END CATCH 
0

你可以嘗試使用TransactionScope的

Using scope As TransactionScope = New TransactionScope 
Try 
'Here will be the DB call code 
'Make some verifications if everyting was ok in DB 
SCope.Complete() 

Catch ex As Exception 
End Try 
End Using 

我不會用從SQL BEGIN TRY TRY END由於沒有抓住所有的時間,如果一個錯誤發生。例如,如果您調用一個方法拋出一個鏈接服務器,並且鏈接服務器上發生錯誤,則開始嘗試結束嘗試不會捕獲該錯誤:另外「TRY ... CATCH構造捕獲嚴重度高於10的所有執行錯誤不關閉數據庫連接。「

如果您使用TRANSACTIONSCOPE,則可以從SQL中刪除TRANSACTION。如果由於腳本執行後的錯誤或驗證而導致scope.Complete()未被調用,則所有內容都將回滾。