0

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

在故障排除过程中,我试图操纵@JobStartaftersp_start_job执行的值。同样,我可以在 SSMS 中这样做并接收预期的结果,但从 .NET 中,变量仍将包含初始化值。

我愿意接受任何可以解释为什么它在 SSMS 而不是 .NET 中运行良好的信息,以及如何让它在 .NET 中运行。谢谢。

4

1 回答 1

0

我修改了我的存储库方法以使用 ADO.NET 来调用我的存储过程。最初,我使用数据上下文来执行此操作。无论出于何种原因,它现在正确填充JobStartResult. 因此,代码现在按预期工作。

但是,我不知道为什么存储过程在通过数据上下文调用和通过 ADO.NET 调用时表现不同。

于 2013-04-24T14:17:16.777 回答