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

.NET Core Quartz任务访问SQL Server表报错:对象名'Reports.PreviousReportResult'无效

问题:Quartz任务访问SQL Server表时提示"Invalid object name"错误

问题场景

在.NET Core项目中使用Quartz执行后台任务,任务执行时访问PreviousReportResult表报错,其他表访问正常。SSMS中直接查询该表无问题,但代码中无论用EF Core还是直接SQL都提示表不存在。

Quartz任务代码

public class ReportsChangesJob : IJob
{
    private readonly IReportsService _reportsService;

    public ReportsChangesJob(IReportsService reportsService)
    {
        _reportsService = reportsService;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        await _reportsService.CheckReportsChanges(context.CancellationToken);
    }
}

表访问代码

通过仓储访问表的代码:

var change = await _repository.Get<PreviousReportResult>(e => e.ReportId == report.Id);

直接SQL访问的代码:

string sql = "SELECT TOP(1) [Id], [ItemsCount], [Json], [ReportId] FROM [Reports.PreviousReportResult] WHERE [ReportId] = @reportId";
var result = await Context.PreviousReportResults.FromSqlRaw(sql, new SqlParameter("@reportId", reportId)).ToListAsync();
return result.FirstOrDefault();

错误日志

Quartz.Core.ErrorLogger[0]
Job DEFAULT.ReportsChangesJob threw an exception.
Quartz.SchedulerException: Job threw an unhandled exception.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name 'Reports.PreviousReportResult'.
at Microsoft.Data.SqlClient.SqlCommand.<>c.b__188_0(Task1 result) at System.Threading.Tasks.ContinuationResultTaskFromResultTask2.InnerInvoke()
at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)...

实体配置与迁移代码

实体配置:

public class PreviousReportResultConfiguration : IEntityTypeConfiguration<PreviousReportResult>
{
    public void Configure(EntityTypeBuilder<PreviousReportResult> builder)
    {
        builder.ToTable("Reports.PreviousReportResult");

        builder.HasOne(e => e.Report)
            .WithOne()
            .HasForeignKey<PreviousReportResult>(e => e.ReportId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

迁移代码:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn<bool>(
        name: "NotificationOnChange",
        table: "Reports.Reports",
        type: "bit",
        nullable: false,
        defaultValue: false);

    migrationBuilder.CreateTable(
        name: "Reports.PreviousReportResult",
        columns: table => new
        {
            Id = table.Column<int>(type: "int", nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            ItemsCount = table.Column<int>(type: "int", nullable: false),
            Json = table.Column<string>(type: "nvarchar(max)", nullable: true),
            ReportId = table.Column<int>(type: "int", nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Reports.PreviousReportResult", x => x.Id);
            table.ForeignKey(
                name: "FK_Reports.PreviousReportResult_Reports.Reports_ReportId",
                column: x => x.ReportId,
                principalTable: "Reports.Reports",
                principalColumn: "Id",
                onDelete: ReferentialAction.Cascade);
        });

    migrationBuilder.CreateIndex(
        name: "IX_Reports.PreviousReportResult_ReportId",
        table: "Reports.PreviousReportResult",
        column: "ReportId",
        unique: true);
}

说明:已将配置添加到DbContext,创建了对应的DbSet。


排查思路与解决办法

1. 修正架构与表名的定义方式

SQL Server中架构和表名的正确分隔格式是[架构名].[表名],你当前的写法将Reports.PreviousReportResult当作了单个表名,而非Reports架构下的PreviousReportResult表。

实体配置修改:

将实体配置中的表名写法改为EF Core标准的架构+表名格式:

builder.ToTable("PreviousReportResult", "Reports");

第一个参数是表名,第二个参数是架构名。

2. 修正迁移代码中的表定义

迁移代码需明确区分架构和表名,修改如下:

migrationBuilder.CreateTable(
    name: "PreviousReportResult",
    schema: "Reports",
    columns: table => new
    {
        Id = table.Column<int>(type: "int", nullable: false)
            .Annotation("SqlServer:Identity", "1, 1"),
        ItemsCount = table.Column<int>(type: "int", nullable: false),
        Json = table.Column<string>(type: "nvarchar(max)", nullable: true),
        ReportId = table.Column<int>(type: "int", nullable: false)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_PreviousReportResult", x => x.Id);
        table.ForeignKey(
            name: "FK_PreviousReportResult_Reports_ReportId",
            column: x => x.ReportId,
            principalSchema: "Reports",
            principalTable: "Reports",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);
    });

migrationBuilder.CreateIndex(
    name: "IX_PreviousReportResult_ReportId",
    schema: "Reports",
    table: "PreviousReportResult",
    column: "ReportId",
    unique: true);

3. 修正直接SQL语句中的表名

将SQL中的表名改为[Reports].[PreviousReportResult]:

string sql = "SELECT TOP(1) [Id], [ItemsCount], [Json], [ReportId] FROM [Reports].[PreviousReportResult] WHERE [ReportId] = @reportId";

4. 验证连接字符串与数据库权限

  • 确认DbContext的连接字符串指向正确的数据库实例和库名,避免连接到无该表的数据库。
  • 检查应用程序使用的数据库登录用户是否拥有Reports架构的访问权限,避免因权限不足导致表无法识别。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 00:02:32