2012-02-09 100 views
7

我正試圖將Red Gate的SQLBackup Pro軟件整合到我用C#編寫的內部備份軟件中。自然的做法是通過他們的Extended Stored Procedure。問題在於它被稱爲我從未見過的格式:如何使用非常規參數調用存儲過程?

master..sqlbackup '-SQL "BACKUP DATABASE pubs TO DISK = [C:\Backups\pubs.sqb]"' 

這在通過SSMS運行時工作得很好。我遇到麻煩的地方是試圖從C#調用它(使用.NET 4和Dapper Dot Net)。

我第一次嘗試不起作用,因爲它解釋了整個cmd字符串作爲存儲過程的名稱,並引發錯誤「無法找到存儲過程‘’」:

var cmd = "master..sqlbackup '-SQL \"BACKUP DATABASE pubs TO DISK = [C:\\Backups\\pubs.sqb]\"'"; 
connection.Execute(cmd, commandType: CommandType.StoredProcedure, commandTimeout: 0); 

我的第二次嘗試立即返回並出現(以C#)成功,但沒有備份實際上被採用(這也吮吸參數):

var cmd = "master..sqlbackup"; 
var p = new DynamicParameters(); 
p.Add("", "'-SQL \"BACKUP DATABASE pubs TO DISK = [C:\\Backups\\pubs.sqb]\"'"); 
connection.Execute(cmd, p, commandType: CommandType.StoredProcedure, commandTimeout: 0); 

我的第三次嘗試也似乎是成功的,但沒有備份實際上被採用:

var cmd = "master..sqlbackup '-SQL \"BACKUP DATABASE pubs TO DISK = [C:\\Backups\\pubs.sqb]\"'"; 
connection.Execute(cmd, commandTimeout: 0); 

我錯過了什麼?

更新1:

我忽略了紅門文檔,說的存儲過程實際上不會提高SQL錯誤,它只是在輸出表返回錯誤。油滑。這也許可以解釋爲什麼我在上面的第二個和第三個測試中發現沉默失敗:一些潛在的問題,他們沒有收集輸出以顯示原因。

這是我現在所在:

var cmd = "master..sqlbackup"; 
var p = new DynamicParameters(); 
p.Add("", "'-SQL \"BACKUP DATABASE pubs TO DISK = [C:\\Backups\\pubs.sqb]\"'"); 
p.Add("@exitcode", DbType.Int32, direction: ParameterDirection.Output); 
p.Add("@sqlerrorcode", DbType.Int32, direction: ParameterDirection.Output); 
connection.Execute(cmd, p, commandType: CommandType.StoredProcedure, commandTimeout: 0); 

當我運行這一點,並檢查這些輸出參數,我得到退出代碼870:

無命令傳遞到S​​QL備份。

該命令爲空。

所以它沒有看到空名的參數。

更新2:

捕捉上面的跟蹤顯示空參數字符串結束了@Parameter1=更換這就解釋了爲什麼在存儲過程並不這麼看。

+0

在sqlbackup上執行sp_help,我確信該參數的名稱爲 – 2012-02-10 06:28:09

+0

'sp_help sqlbackup'只包含名稱,所有者,類型和Created_datetime列。儘管類型是「擴展存儲過程」,但沒有param_order(或任何它被稱爲)列... – 2012-02-10 16:03:47

+0

我打開了一個紅門案例來了解該參數是否有名稱。我們拭目以待。 – 2012-02-10 16:38:09

回答

2

這是毛,而不是在所有我想要的東西,但是這是我有什麼現在的工作:

var cmd = String.Format(@" 
DECLARE @exitcode int; 
DECLARE @sqlerrorcode int; 
EXEC master..sqlbackup '-SQL \"BACKUP DATABASE [{0}] TO DISK = [{1}])\"', @exitcode OUTPUT, @sqlerrorcode OUTPUT; 
IF (@exitcode >= 500) OR (@sqlerrorcode <> 0) 
BEGIN 
RAISERROR('SQLBackup failed with exitcode %d and sqlerrorcode %d ', 16, 1, @exitcode, @sqlerrorcode) 
END 
", myDbName, myBkpPath); 

connection.Execute(cmd, commandTimeout: 0); 

此執行備份和實際返回失敗狀態,這暴露導致的潛在的問題失敗部分失敗。

它運行之前,myDbName是針對已知的數據庫列表檢查,以確保它的存在和myBkpPath由我的代碼生成的,所以我不擔心注射。只是......好吧,看看那個。可怕。

2

你的第一次嘗試看起來幾乎是正確的。我注意到的是你沒有逃過反斜槓。對於這種情況,使用@前綴來禁用字符串轉義通常更容易。此外,你想以exec來預先考慮並使其CommandType.Text

編輯:固定我自己逃逸的bug這裏

var cmd = @"exec 'master..sqlbackup -SQL ""BACKUP DATABASE pubs TO DISK = [C:\Backups\pubs.sqb]""'"; 
connection.Execute(cmd, commandType: CommandType.Text, commandTimeout: 0); 
+0

對不起,反斜槓實際上已經逃脫,但沒有通過問題。我選擇了轉義它們而不是使用'@「」'語法,因爲引號已經是最容易混淆的部分,並且路徑(一旦計算出來)將通過參數或(god forbid)字符串格式插入。 – 2012-02-09 20:14:23

+0

您是否嘗試添加exec,因爲我也提到過? – 2012-02-09 20:22:09

+0

是的。與#2和#3相同的結果:立即返回而沒有做任何工作,但似乎沒有失敗。 – 2012-02-10 15:34:37

0

您是否嘗試過創建調用擴展存儲過程的典型存儲過程,並調用從代碼?看起來你只有幾個參數來處理這裏。

+0

我相信這樣做可行,但不是一個非常可擴展的解決方案,因爲有問題的存儲過程必須在我的每個SQL服務器上創建和管理。 – 2012-02-09 20:15:48

+0

不是每臺服務器上的擴展存儲過程? '管理'是什麼意思? – ScottE 2012-02-10 03:30:22

+0

擴展存儲過程是具有網絡感知安裝程序的軟件包的一部分,可讓您輕鬆地將其推送到網絡並在網絡上進行升級。我並不是說這對存儲過程來說是不可能的,但是我寧願讓我的代碼與已經存在的代碼一起工作。 – 2012-02-10 15:33:49

0

您在測試中遇到了幾個問題。

在第一個中,您設置了CommandType.StoredProcedure。你應該將它設置爲CommandType.Text,這樣它就足夠聰明,只需傳遞該字符串即可執行。

在後面的例子中,你並沒有給參數一個名字。看看他們的SqlBackup過程,看看參數名稱是什麼。然後使用它。否則,將不會分配給它。

+0

這兩個問題在我的問題中解釋。第一個:「我的第一次嘗試不起作用,因爲它將整個cmd字符串解釋爲存儲過程的名稱,並引發錯誤無法找到存儲過程」「。我的第三次嘗試就是這樣,但備份默默地失敗了。第二,看看我對我的問題的評論。該參數沒有文檔名稱。 – 2012-02-12 03:57:51

+0

@ sh-beta:您可以檢查proc以確定參數名稱。無需文件。即使加密過程也會告訴你參數的名字是什麼。在管理工作室中,您可以擴展存儲的proc定義並查看參數列表。或者您可以右鍵單擊proc並編寫腳本,以便您可以獲取參數的名稱。 – NotMe 2012-02-13 02:24:49

+0

這一個不給任何有用的東西。整個腳本定義是「EXEC dbo.sp_addextendedproc N'sqlbackup',''」 – 2012-02-15 18:41:10

相關問題