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

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();
问题原因与解决方法

核心原因

  1. 属性访问权限限制:Baseclass中name、information属性的setter为internal,Entity Framework 6(.NET 4.8对应的版本)默认需要公共(public)setter才能正常跟踪和持久化属性值。权限不足会导致EF无法写入这些字段,最终只生成Id列的插入语句。

  2. 实体重复添加干扰:保存逻辑中,Derived_B实例会同时匹配item is Derived_B和item is Derived_A两个条件,导致同一个实体被先后添加到Derived_Bs和Derived_As两个DbSet中,干扰EF的实体状态跟踪逻辑,进一步加剧属性持久化异常。

解决步骤

  1. 修改属性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
  1. 修复重复添加逻辑
    使用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);
    }
}
  1. 验证继承映射配置
    当前通过ToTable配置的TPT(每个实体类对应独立表)继承映射,EF 6对SQLite是兼容的,无需额外调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:14:52