2012-02-09 102 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

相关问题