手动新增EF Core实体后需添加[Table]特性才能访问SQL表的原因咨询
问题描述
我有一个已在生产环境运行3年的C# Razor应用(SQL后端)。近期手动在SQL中新增了3张表,没有通过Package Manager Console添加迁移,直接修改现有DBContext类添加了3个新的DbSet:
public virtual DbSet<PaymentPlan> oDbSetPmtPlan { get; set; }
同时在Models目录新增了3个实体类,并修改了一个需要从新表获取数据的现有Razor页面。本地数据库是生产库的副本,但每次运行项目时,访问引用新表的页面都会出现「无效对象」错误,相关代码如下:
public IList<Models.PaymentPlan> OPmtPlansList { get; set; } . . . public async Task<IActionResult> OnGetAsync(string id) { . . OPmtPlansList = await _dbWriterContext.oDbSetPmtPlan.Where(m => m.ToBalance <= TotalBalanceDue).ToListAsync(); }
最终在PaymentPlan实体类中添加[Table("PaymentPlan")]特性后问题解决:
namespace Customer_BlahBlah.Models { [Table("PaymentPlan")] public partial class PaymentPlan { [Key] public Guid PlanId { get; set; }
让我困惑的是,其他现有实体类从未使用该特性却仍能正常执行CRUD操作,且对比后发现新表在SSMS中的设计与现有表并无差异,调试排查后仍无法理解原因。
当前项目NuGet包版本
Id Versions ProjectName -- -------- ----------- Microsoft.Extensions.Configuration.UserSecrets {6.0.1} Customer Blah IBM.Data.DB2.Core {3.1.0.600} Customer Blah Microsoft.VisualStudio.Web.CodeGeneration.Design {5.0.2} Customer Blah MailKit {3.3.0} Customer Blah Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation {6.0.8} Customer Blah Microsoft.EntityFrameworkCore {6.0.8} Customer Blah Microsoft.EntityFrameworkCore.SqlServer {6.0.8} Customer Blah System.Linq.Dynamic.Core {1.2.19} Customer Blah Microsoft.CodeAnalysis.CSharp.Workspaces {4.2.0} Customer Blah EntityFramework.IBM.DB2 {6.4.1} Customer Blah Microsoft.AspNetCore.Identity.EntityFrameworkCore {6.0.8} Customer Blah Net.IBM.Data.Db2 {6.0.0.200} Customer Blah EntityFramework {6.4.4} Customer Blah Microsoft.EntityFrameworkCore.Relational {6.0.8} Customer Blah Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore {6.0.8} Customer Blah Microsoft.AspNetCore.Identity.UI {6.0.8} Customer Blah MimeKit {3.4.0} Customer Blah Microsoft.EntityFrameworkCore.Tools {6.0.8} Customer Blah IBM.EntityFrameworkCore {6.0.0.200} Customer Blah
目前有16个包待更新,但打算先弄清楚这个问题再进行更新。
补充:PaymentPlan表创建SQL脚本
CREATE TABLE [dbo].[PaymentPlan]( [PlanId] [int] IDENTITY(1,1) NOT NULL, [FromBalance] [numeric](6, 2) NOT NULL, [ToBalance] [numeric](6, 2) NOT NULL, [MaxMonthsLimit] [int] NOT NULL, CONSTRAINT [PK_PaymentPlan] PRIMARY KEY CLUSTERED ( [PlanId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'The Plan Unique Identifier' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'PaymentPlan', @level2type=N'COLUMN',@level2name=N'PlanId' GO
问题原因与解决说明
核心原因:EF Core表名约定不匹配
你遇到的「无效对象」错误,本质是EF Core默认表名规则与实际数据库表名冲突:
- EF Core默认会将DbSet的属性名作为表名,而非实体类名。你定义的DbSet是
oDbSetPmtPlan,所以EF Core会尝试查询名为oDbSetPmtPlan的表,但实际数据库中表名是PaymentPlan,自然找不到对象。 - 现有实体类无需
[Table]特性,是因为它们对应的DbSet属性名和数据库表名完全一致。比如某个实体类Customer对应的DbSet是public DbSet<Customer> Customer { get; set; },EF Core默认就能匹配到同名表。
额外注意点
你的实体类中PlanId定义为Guid类型,但数据库中PlanId是int自增主键,这虽然不是本次错误的直接原因,但后续会引发类型转换异常,建议同步修正:
[Key] public int PlanId { get; set; }
其他可选解决方案
除了添加[Table]特性,还可以通过Fluent API在DbContext的OnModelCreating方法中配置表名:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<PaymentPlan>().ToTable("PaymentPlan"); // 其他实体配置... }
内容的提问来源于stack exchange,提问作者GCDevOps
相关产品推荐
相关产品推荐

