sp_start_job
当我在存储过程中使用它时,我遇到了一个令人沮丧的问题,将其结果存储在一个变量中,然后选择该变量以供 .NET 使用。当我的 SP 在 Management Studio 查询窗口中运行时,它可以完美运行,所以我不知道出了什么问题。
我有一个由我的 SP 的结果集填充的对象:
public class SQLServerAgentResult : StoredProcResult
{
public int? JobStatus { get; set; }
public int? JobStartResult { get; set; } //This is the property for the result of sp_start_job
public int? LastJobResult { get; set; }
}
此方法使用数据上下文填充它:
public IList<SQLServerAgentResult> ExecuteSqlAgent(string JobName, bool? RunJob, TimeSpan? PollingInterval)
{
const string myName = "usp_Run_Monitor_Agent_Job";
List<SqlParameter> spParams = new List<SqlParameter>();
spParams.Add(new SqlParameter()
{
DbType = System.Data.DbType.String,
ParameterName = "JobName",
Value = JobName
});
string sp_exec = "usp_Run_Monitor_Agent_Job @JobName";
if (RunJob != null)
{
spParams.Add(new SqlParameter()
{
SqlDbType = System.Data.SqlDbType.Bit,
DbType = System.Data.DbType.Boolean,
ParameterName = "RunJob",
Value = RunJob
});
sp_exec += ", @RunJob";
}
if (PollingInterval != null)
{
spParams.Add(new SqlParameter()
{
SqlDbType = System.Data.SqlDbType.VarChar,
DbType = System.Data.DbType.Time,
ParameterName = "TimerDelay",
Value = PollingInterval
});
sp_exec += ", @TimerDelay";
}
try
{
Context.CommandTimeout = 120;
List<SQLServerAgentResult> result = Context.SQLServerAgentResult.SqlQuery(sp_exec, spParams.ToArray()).ToList();
return result;
}
catch (Exception ex)
{
log.Error(myName + " error", ex);
throw ex;
}
}
应该注意的是,这个对象总是用我的存储过程中的数据填充的,JobStatus
而且LastJobResult
总是正确的。但是,JobStartResult
应该包含 的结果的sp_start_job
,只有存储过程中使用的变量的初始化值(在本例中为空值)。这可能是一个有效的结果(SP 可以决定不运行sp_start_job
),但是当sp_start_job
完成时,结果似乎没有保存到变量中,而我的对象将包含初始化值。
这是我的 SQL 代理 SP:
CREATE PROCEDURE usp_Run_Monitor_Agent_Job @JobName NVARCHAR(MAX), @RunJob BIT = 1, @TimerDelay VARCHAR(50) = '00:00:01'
AS
DECLARE @JobStatus INT
DECLARE @JobStart INT
DECLARE @JobResult INT
DECLARE @SQL NVARCHAR(MAX)
DECLARE @Params NVARCHAR(MAX)
DECLARE @IsProcessing BIT
SET @JobStatus = 0 --Works fine in .NET
SET @JobStart = null --If this is initialized as -1, 5, or 43276852349, then that is the result I will see in .NET, without exception
SET @JobResult = 0 --Works fine in .NET
SET @IsProcessing = 0
SET @SQL = N'SELECT @JobStatus_OUT = current_execution_status FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''EXEC MSDB.dbo.sp_help_job @job_name = ''''' + @JobName + ''''', @job_aspect = ''''JOB'''' '')'
SET @Params = N'@JobStatus_OUT INT OUTPUT'
--Check to see if the job is currently running
EXEC sp_executesql @SQL, @Params, @JobStatus_OUT = @JobStatus OUTPUT;
--Check to see if the job is idle
IF @JobStatus = 4
BEGIN
--Check to see if we should run the job
IF @RunJob = 1
BEGIN
--This next line is the problem. It runs, but @JobStart doesn't contain the result of the sp_start_job when run through .NET.
EXEC @JobStart = MSDB.dbo.sp_start_job @Job_Name = @JobName
SET @IsProcessing = 1
WHILE @IsProcessing = 1
BEGIN
--Now we need to wait for the job to finish
WAITFOR DELAY @TimerDelay
EXEC sp_executesql @SQL, @Params, @JobStatus_OUT = @JobStatus OUTPUT;
--4 is "idle"
--5 is "suspended", which means the job isn't running but it won't be able to be re-executed either
IF @JobStatus = 4 OR @JobStatus = 5
SET @IsProcessing = 0
END
END
END
SET @SQL = N'SELECT TOP 1 @JobResult_OUT = run_status FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'', ''SET FMTONLY OFF; EXEC MSDB.dbo.sp_help_jobhistory @job_name = ''''' + @JobName + ''''', @mode = ''''FULL'''' '') WHERE step_id = 0 ORDER BY run_date DESC, run_time DESC;'
SET @Params = N'@JobResult_OUT AS INT OUTPUT'
EXEC sp_executesql @SQL, @Params, @JobResult_OUT = @JobResult OUTPUT;
--Return job statuses
SELECT CAST(1 AS BIGINT) AS ID, @JobStatus AS JobStatus, @JobStart AS JobStartResult, @JobResult AS LastJobResult
在故障排除过程中,我试图操纵@JobStart
aftersp_start_job
执行的值。同样,我可以在 SSMS 中这样做并接收预期的结果,但从 .NET 中,变量仍将包含初始化值。
我愿意接受任何可以解释为什么它在 SSMS 而不是 .NET 中运行良好的信息,以及如何让它在 .NET 中运行。谢谢。