CTP 4 не учитывает свойства базового класса

В следующем примере CTP учитывает только свойства класса User, но я ожидаю, что свойства базового класса включены в таблицу Users.

Есть ли способ сказать, что CTP включает свойства базового класса? Или какое может быть альтернативное решение?

class PersonDBContext : DbContext
{
    public DbSet<User> UserSet { get; set; }
}
class Person
{
    public string Firstname { get; set; }
    public string SurName { get; set; }
}
class User : Person
{
    public int UserId { get; set; }
    public string CreatedOn { get; set; }
}

1 ответ

Решение

Это потому что ты объявил DbSet<User> в вашем DbContext вместо DbSet<Person>, EF-код сначала имеет понятие достижимости, когда речь заходит о наследовании, что в основном означает, что если вы поместите набор базового класса в контекст, он пойдет вниз, найдет и включит все свои подклассы.

Здесь есть еще одна проблема: вы не указали первичный ключ для своего Person класс и EF также не могли сделать вывод, основанный на соглашениях Code First. По умолчанию EF отображает наследование в модели на TPH (тип на иерархию) в базе данных, а подкласс наследует ключ от своего базового класса, который был помещен в подкласс (т. Е. UserId) в вашей модели.

Чтобы исправить это, мы сначала изменим DbSet на DbContext, чтобы иметь тип Person и тогда нам нужно двигаться вверх 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; }        
}

Результатом этой модели будет следующая схема БД, в которой есть все столбцы обоих классов (обратите внимание, поддержка множественного числа):

альтернативный текст

Как изменить TPH на TPT (таблица на иерархию) в Code First:

Как я уже сказал, в соответствии с соглашением, код EF сначала будет использовать TPH для отображения наследования в базе данных, а чтобы изменить его на TPT, нам нужно переопределить соглашения с помощью Fluent API:

public class StackruContext : 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 (таблица для конкретного типа) в Code First:

В таблице для каждого конкретного класса есть таблица для каждого класса, и у каждой из этих таблиц есть столбец для каждого свойства этого типа.

Код для этого показан ниже, обратите внимание, что я отключаю идентификацию в свойстве первичного ключа, потому что между двумя таблицами нет внешнего ключа, и мы должны позаботиться о предоставлении уникальных ключей.

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");
}

Эта модель приведет к следующей схеме БД:альтернативный текст

Другие вопросы по тегам