请参阅下面的代码示例,其中我尝试实现与 SQLite 数据库的代码优先连接。我正在使用 .NET 4.8(不是 Core)。所有列名和数据库表名都是正确的。
Id
是所有数据库表中唯一的主键。 Derived_B
和 Derived_A
的数据库表是不同的。两者都有 Id
、Name
和 Information
列。
Widgets
表通过上面代码中未列出的附加整数列与 Id
中的 Derived_B
具有外键关系。我可以以编程方式创建 Derived_A
、Derived_B
和 Widgets
的实例,将它们添加到 Example_DataContext
,然后调用 SaveChanges()
。
随后,
Derived_A
和 Widgets
的有效条目将写入数据库。 Widgets
表中的新条目与 Derived_B
表具有有效的外键关系。
这就是我陷入困境的地方——虽然条目数量似乎正确,但
Derived_B
中的新条目除了索引列之外都是空的。数据上下文的记录输出表明仅 ID 列被写入 Derived_B
。为什么?我错过了什么?
我希望
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();
如果您希望每个子类包含共享列,您需要显式告诉 EF 使用 Table-per-Concrete 配置,否则它可能会假设由于 B 继承自 A,而 A 继承自 Base,那么 Base 或“ A”将包含名称和其他列,B 的 Id 将链接回 A 以将两者关联起来。
modelBuilder.Entity<Baseclass>().UseTpcMappingStrategy();
modelBuilder.Entity<Derived_A>().UseTpcMappingStrategy();
老实说,当涉及到 EF 实体时,我会避免深度继承,以及几乎任何继承。代码如下:
if (item is Derived_B derivedB)
{
dbContext.Derived_Bs.Add(derivedB);
}
if (item is Derived_A derivedA)
{
dbContext.Derived_As.Add(derivedA);
}
对于可维护性来说是一个值得注意的危险信号。