如何使用非常规参数调用存储过程?

我试图将Red Gate的SQLBackup Pro软件整合到我用C#编写的内部备份软件中。 自然的做法是通过扩展存储过程。 问题在于它以我从未见过的格式被调用:

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

这在通过SSMS运行时工作得很好。 我遇到麻烦的地方是试图从C#调用它(使用.NET 4和Dapper Dot Net)。

我的第一次尝试不起作用,因为它将整个cmd字符串解释为存储过程的名称,并引发错误“无法找到存储过程”“:

var cmd = "master..sqlbackup '-SQL "BACKUP DATABASE pubs TO DISK = [C:Backupspubs.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:Backupspubs.sqb]"'");
connection.Execute(cmd, p, commandType: CommandType.StoredProcedure, commandTimeout: 0);

我的第三次尝试似乎也成功了,但实际上没有进行备份:

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

我错过了什么?

更新1:

我忽略了Red Gate文档说存储过程实际上不会引发SQL错误,它只是在输出表中返回错误。 油滑。 这也许可以解释为什么我在上面的第二个和第三个测试中发现沉默失败:一些潜在的问题,他们没有收集输出以显示原因。

这就是我现在的位置:

var cmd = "master..sqlbackup";
var p = new DynamicParameters();
p.Add("", "'-SQL "BACKUP DATABASE pubs TO DISK = [C:Backupspubs.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:

没有命令传递给SQL备份。

该命令是空的。

所以它没有看到空名的参数。

更新2:

在跟踪中捕获上述内容显示空参数字符串最终以@Parameter1=取代,这解释了存储过程为何看不到它。


你的第一次尝试看起来几乎正确 我注意到的是你没有逃过反斜杠。 对于这种情况,使用@前缀来禁用字符串转义通常更容易。 另外,你想用exec命令并使其成为CommandType.Text

编辑:修复我自己在这里逃跑的错误

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

这很糟糕,根本不是我想要的,但这是我现在正在工作的东西:

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由我的代码生成,所以我不担心注入。 只是......好吧,看看那个。 可怕。


您是否尝试过创建一个调用扩展存储过程的典型存储过程,并从代码中调用该过程? 看起来你只有几个参数来处理这里。

链接地址: http://www.djcxy.com/p/57357.html

上一篇: How do I call a stored procedure with unconventional parameters?

下一篇: Compiling ICU using arm