Это потому, что вы объявили DbSet<User>
в своем DbContext вместо DbSet<Person>
. EF-код сначала имеет концепцию достижимости , когда дело доходит до наследования, что в основном означает, что если вы поместите набор базового класса в контекст, он пойдет вниз, найдет и включит все свои подклассы.
Здесь также есть еще одна проблема: вы не указали первичный ключ для своего Person
класса, и EF также не может вывести его на основе соглашений Code First. По умолчанию EF отображает наследование в модели на TPH (тип на иерархию) в базе данных, а подкласс наследует ключ от своего базового класса, который был помещен в подкласс (т.е. UserId) в вашей модели.
Чтобы исправить это, мы сначала изменим DbSet на DbContext на тип Person
, а затем нам нужно переместиться на UserId
к базовому классу Person
и сделать его Key как следующим образом:
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; }
}
Эта модель приведет к следующей схеме БД, в которой есть все столбцы обоих классов (обратите внимание, поддержка множественного числа):
Как изменить TPH на TPT (таблица на иерархию) в первом коде:
Как я уже сказал, условно, код 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");
}
}
Эта модель приведет к следующей схеме БД:
Как изменить TPH на TPC (таблица для конкретного типа) в первом коде:
В таблице для каждого конкретного класса есть таблица для каждого класса, и у каждой из этих таблиц есть столбец для каждого свойства этого типа.
Код для этого показан ниже, обратите внимание, что я отключаю идентификацию в свойстве первичного ключа, потому что между двумя таблицами нет внешнего ключа, и мы должны позаботиться о предоставлении уникальных ключей.
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");
}
Эта модель приведет к следующей схеме БД: