Entity Framework Code-First写入SQLite时Derived_B数据为空的问题排查
在.NET 4.8(非Core)环境下使用Entity Framework Code-First连接SQLite数据库,所有列名与表名均正确,Id为各表唯一主键。Derived_A和Derived_B为独立表,均包含Id、Name和Information列;Widgets表通过未列出的整数列与Derived_B的Id建立外键关联。
创建Derived_A、Derived_B和Widgets实例并添加至Example_DataContext调用SaveChanges()后,Derived_A和Widgets的数据库条目正常,Widgets与Derived_B的外键关联有效,但Derived_B的新条目仅Id列有值,其余字段为空,数据上下文日志显示仅Id列被写入Derived_B表。请问这是什么原因?遗漏了什么?
相关代码如下:
using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; namespace entityExample { class Baseclass { [Column(name:"Name")] public string name { get; internal set; } [Column(name: "Information")] public string information { get; internal set; } } [Table("Derived_A")] class Derived_A : Baseclass { [Column(name: "Id")] public int Id { get; set; } public Derived_A() {} } [Table("Derived_B")] class Derived_B : Derived_A { public Derived_B() {} public List<Widget> widgets { get; internal set; } } [Table("Widgets")] class Widget { [Column(name: "Id")] public int Id { get; set; } [Column(name: "Name")] public string name { get; internal set; } [Column(name: "Description")] public string description { get; internal set; } } class Example_DataContext : DbContext { public DbSet<Derived_A> Derived_As {get; set;} public DbSet<Derived_B> Derived_Bs { get; set;} public DbSet<Widget> Widgets { get; set;} protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.Log = s => System.Diagnostics.Debug.WriteLine(s); modelBuilder.Entity<Derived_A>().ToTable("Derived_A"); modelBuilder.Entity<Derived_B>().ToTable("Derived_B"); } } }
保存数据的代码:
foreach (Baseclass item in items) { if (item is Derived_B derivedB) { dbContext.Derived_Bs.Add(derivedB); } if (item is Derived_A derivedA) { dbContext.Derived_As.Add(derivedA); } } dbContext.SaveChanges();
核心原因
属性访问权限限制:
Baseclass中name、information属性的setter为internal,Entity Framework 6(.NET 4.8对应的版本)默认需要公共(public)setter才能正常跟踪和持久化属性值。权限不足会导致EF无法写入这些字段,最终只生成Id列的插入语句。实体重复添加干扰:保存逻辑中,
Derived_B实例会同时匹配item is Derived_B和item is Derived_A两个条件,导致同一个实体被先后添加到Derived_Bs和Derived_As两个DbSet中,干扰EF的实体状态跟踪逻辑,进一步加剧属性持久化异常。
解决步骤
- 修改属性setter为public
将所有需要持久化的属性setter改为public,确保EF能正常访问并写入数据:
class Baseclass { [Column(name:"Name")] public string name { get; set; } [Column(name: "Information")] public string information { get; set; } } // Derived_A、Derived_B、Widget类的属性setter同理修改为public
- 修复重复添加逻辑
使用else if避免同一个实体被重复添加到多个DbSet:
foreach (Baseclass item in items) { if (item is Derived_B derivedB) { dbContext.Derived_Bs.Add(derivedB); } else if (item is Derived_A derivedA) { dbContext.Derived_As.Add(derivedA); } }
- 验证继承映射配置
当前通过ToTable配置的TPT(每个实体类对应独立表)继承映射,EF 6对SQLite是兼容的,无需额外调整。
内容的提问来源于stack exchange,提问作者Henry

