CTP 4 не учитывает свойства базового класса - PullRequest
2 голосов
/ 06 декабря 2010

В приведенном ниже примере 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 Ответ

3 голосов
/ 06 декабря 2010

Это потому, что вы объявили 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; }        
}

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

alt text

Как изменить 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");
    }
}

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

alt text

Как изменить 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");
}

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

...