DbSet<User>
これは、の代わりに DbContext で宣言したためですDbSet<Person>
。EF コードには、継承に関して最初に到達可能性の概念があります。これは基本的に、基本クラスのセットをコンテキストに配置すると、そのサブクラスをすべて見つけて含めることを意味します。
ここにはもう 1 つの問題があります。Person
クラスの主キーを指定していないため、EF は Code First 規則に基づいて主キーを推測できませんでした。デフォルトでは、EF はモデルの継承をデータベースの TPH (Type Per Hierarchy) にマップし、サブクラスは、モデルのサブクラス (つまり UserId) に配置された基本クラスからキーを継承します。
これを修正するには、まず DbContext の DbSet を型に変更してから、次のように基本クラスPerson
に移動してそれをKeyにする必要があります。UserId
Person
public class Person
{
[Key]
public int UserId { get; set; }
public string Firstname { get; set; }
public string SurName { get; set; }
}
public class User : Person
{
public string CreatedOn { get; set; }
}
public class PersonDBContext : DbContext
{
public DbSet<Person> UserSet { get; set; }
}
このモデルは、両方のクラスのすべての列を持つ次の DB スキーマになります (複数形のサポートに注意してください)。

Code First で TPH を TPT (Table Per Hierarchy) に変更する方法:
私が言ったように、慣例により、EF コードは最初に TPH を使用して継承をデータベースにマップし、それを TPT に変更するには、Fluent API を使用して規則をオーバーライドする必要があります。
public class StackOverflowContext : DbContext
{
public DbSet<Person> Persons { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().MapHierarchy(p => new
{
p.UserId,
p.Firstname,
p.SurName,
})
.ToTable("Person");
modelBuilder.Entity<User>().MapHierarchy(u => new
{
u.UserId,
u.CreatedOn
})
.ToTable("User");
}
}
このモデルは、次の DB スキーマになります。

Code First で TPH を TPC (Concrete Type ごとのテーブル) に変更する方法:
Table per Concrete Class には、各クラスのテーブルがあり、それらの各テーブルには、そのタイプのすべてのプロパティの列があります。
このコードを以下に示します。2 つのテーブル間に外部キーがなく、一意のキーを提供する必要があるため、主キー プロパティの ID をオフにしていることに注意してください。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().Property(p => p.UserId)
.StoreGeneratedPattern = System.Data.Metadata.Edm.StoreGeneratedPattern.None;
modelBuilder.Entity<Person>().MapSingleType(p => new
{
p.UserId,
p.Firstname,
p.SurName,
})
.ToTable("Person");
modelBuilder.Entity<User>().MapSingleType(u => new
{
u.UserId,
u.CreatedOn,
u.Firstname,
u.SurName,
})
.ToTable("User");
}
このモデルは、次の DB スキーマになります。
