You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Entity Framework获取SQL作业执行时间,能否获取指定作业最新执行时间?

当然可以通过Entity Framework检索SQL Server Agent作业的相关数据,包括指定作业的最近一次执行时间。SQL Server Agent的作业信息都存储在msdb数据库的系统表中,我们可以通过EF直接查询这些表,下面是两种常用的实现方式:

方法一:使用原生SQL查询(简单直接)

这种方式不需要额外配置实体映射,直接执行原生SQL语句来获取结果,适合只需要查询执行时间这类简单需求的场景。

首先,我们需要利用msdb.dbo.sysjobs(存储作业基本信息)和msdb.dbo.sysjobhistory(存储作业执行历史)这两个表,其中sysjobhistory的run_date(格式为YYYYMMDD整数)和run_time(格式为HHMMSS整数)字段需要转换为标准的DateTime格式。

示例代码(EF Core):

using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;

// 假设你的DbContext实例为context
var targetJobName = "你的目标作业名称";

var lastExecutionQuery = @"
SELECT TOP 1 
    CONVERT(DATETIME, CONVERT(VARCHAR(8), run_date) + ' ' + STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6), run_time), 6), 3, 0, ':'), 6, 0, ':')) AS LastExecutionTime
FROM msdb.dbo.sysjobhistory jh
JOIN msdb.dbo.sysjobs j ON jh.job_id = j.job_id
WHERE j.name = @JobName
AND jh.step_id = 0 -- step_id=0代表整个作业的执行记录(而非单个步骤)
ORDER BY jh.run_date DESC, jh.run_time DESC";

var lastExecutionTime = await context.Database
    .SqlQuery<DateTime>(lastExecutionQuery, new SqlParameter("@JobName", targetJobName))
    .FirstOrDefaultAsync();

if (lastExecutionTime != default)
{
    Console.WriteLine($"作业最近执行时间:{lastExecutionTime}");
}
else
{
    Console.WriteLine("未找到该作业的执行记录");
}

代码说明:

  • step_id = 0:确保我们获取的是整个作业的执行汇总记录,而不是作业内单个步骤的执行记录。
  • 日期转换逻辑:把run_date和run_time的整数格式拼接成标准的日期字符串,再转换为DateTime。
方法二:映射系统表到EF实体(适合复杂场景)

如果需要多次查询作业数据,或者需要获取作业的更多属性(比如作业描述、启用状态等),可以把msdb的系统表映射为EF实体,用LINQ进行查询。

1. 定义实体类

public class SysJob
{
    public Guid job_id { get; set; }
    public string name { get; set; }
    public bool enabled { get; set; }
    // 可以根据需求添加其他字段,比如description、date_created等
}

public class SysJobHistory
{
    public Guid job_id { get; set; }
    public long instance_id { get; set; } // 复合主键的一部分
    public int run_date { get; set; }
    public int run_time { get; set; }
    public int step_id { get; set; }
    // 可以添加其他字段,比如run_status(执行状态:0=失败,1=成功等)
}

2. 在DbContext中配置表映射

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 映射sysjobs表到SysJob实体
    modelBuilder.Entity<SysJob>()
        .ToTable("sysjobs", "dbo")
        .HasKey(j => j.job_id);

    // 映射sysjobhistory表到SysJobHistory实体(复合主键:job_id + instance_id)
    modelBuilder.Entity<SysJobHistory>()
        .ToTable("sysjobhistory", "dbo")
        .HasKey(jh => new { jh.job_id, jh.instance_id });
}

// 在DbContext中添加DbSet
public DbSet<SysJob> SysJobs { get; set; }
public DbSet<SysJobHistory> SysJobHistories { get; set; }

3. 使用LINQ查询最近执行时间

var targetJobName = "你的目标作业名称";

var latestHistory = await (from job in context.SysJobs
                           join history in context.SysJobHistories on job.job_id equals history.job_id
                           where job.name == targetJobName && history.step_id == 0
                           orderby history.run_date descending, history.run_time descending
                           select new { history.run_date, history.run_time })
                           .FirstOrDefaultAsync();

if (latestHistory != null)
{
    // 转换整数格式的日期时间为DateTime
    string dateString = latestHistory.run_date.ToString("D8"); // 转为YYYYMMDD格式字符串
    string timeString = latestHistory.run_time.ToString("D6")
        .Insert(4, ":") // 在第4位插入冒号,转为HHMM:SS
        .Insert(2, ":"); // 在第2位插入冒号,转为HH:MM:SS

    DateTime lastExecTime = DateTime.Parse($"{dateString} {timeString}");
    Console.WriteLine($"作业最近执行时间:{lastExecTime}");
}
else
{
    Console.WriteLine("未找到该作业的执行记录");
}
重要注意事项
  • 权限问题:执行查询的数据库用户需要拥有msdb数据库的SELECT权限,你可以通过以下SQL语句授予权限:
    USE msdb;
    GRANT SELECT ON dbo.sysjobs TO [你的数据库用户名];
    GRANT SELECT ON dbo.sysjobhistory TO [你的数据库用户名];
    
  • 执行状态过滤:如果需要只查询成功的执行记录,可以在查询中添加AND jh.run_status = 1(run_status=1代表执行成功)。

内容的提问来源于stack exchange,提问作者Adrian Borowiec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:46:25