Проблема с отображением наследования TPH в EF 4.1 с Code First - PullRequest
3 голосов
/ 18 сентября 2011

В моем приложении ASP.NET MVC есть следующие классы:

public abstract class Person {
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Student : Person {
    public DateTime RegisteredOnUtc { get; set; }
    public int Age { get; set; }
}

public class Teacher : Person {
    public string LessonName { get; set; }
}

public class PersonMap : EntityTypeConfiguration<Person> {
    public PersonMap()
        : base() {

        this.HasKey(t => t.PersonId);

        this.Property(t => t.FirstName)
            .IsRequired()
            .HasMaxLength(50);

        this.Property(t => t.LastName)
            .IsRequired()
            .HasMaxLength(50);

        this.ToTable("Persons");

        this.Property(t => t.PersonId).HasColumnName("PersonId");
        this.Property(t => t.FirstName).HasColumnName("FirstName");
        this.Property(t => t.LastName).HasColumnName("LastName");

        this.Map<Student>(x => x.Requires("IsStudent").HasValue(true));
        this.Map<Teacher>(x => x.Requires("IsStudent").HasValue(false));
    }
}

public class StudentMap : EntityTypeConfiguration<Student> {
    public StudentMap()
        : base() {

        this.HasKey(t => t.PersonId); // Is this need or not???

        this.ToTable("Persons"); // Is this need or not???

        this.Property(t => t.RegisteredOnUtc).HasColumnName("RegisteredOn");
    }
}

public class TeacherMap : EntityTypeConfiguration<Teacher> {
    public TeacherMap()
        : base() {

        this.HasKey(t => t.PersonId); // Is this need or not???

        this.ToTable("Persons"); // Is this need or not???

        this.Property(t => t.LessonName)
            .IsRequired()
            .HasMaxLength(50);

        this.Property(t => t.LessonName).HasColumnName("Lesson");
    }
}

public class PersonContext : DbContext {

    public ObjectContext ObjectContext {
        get {
            return ((IObjectContextAdapter)this).ObjectContext;
        }
    }

    public DbSet<Person> Persons { get; set; }
    public DbSet<Student> Students { get; set; }
    public DbSet<Teacher> Teachers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
        modelBuilder.Configurations.Add(new PersonMap());
        modelBuilder.Configurations.Add(new StudentMap());
        modelBuilder.Configurations.Add(new TeacherMap());
    }

    public void Detach(object entity) {
        var objectContext = ((IObjectContextAdapter)this).ObjectContext;
        objectContext.Detach(entity);
    }
}

Но, когда я запускаю приложение, получаю эту ошибку:

Свойство 'PersonId' не объявлено для типа 'Student'. Убедитесь, что свойство не было явно исключено из модели с помощью метода Ignore или аннотации данных NotMappedAttribute. Убедитесь, что это допустимое примитивное свойство.

И если удалить this.HasKey(t => t.PersonId); из Student и Teacher, будет выдана эта ошибка:

Указанный ключ отсутствует в словаре.

У вас есть идея, чтобы решить эту проблему, пожалуйста? Спасибо.

Ответы [ 3 ]

1 голос
/ 18 сентября 2011

Вы пытались удалить обе эти строки из StudentMap и TeacherMap?

this.HasKey(t => t.PersonId); // Is this need or not???

this.ToTable("Persons"); // Is this need or not???

Я скопировал ваш код и запустил его без этих строк, и он работал просто отлично.

1 голос
/ 05 октября 2011

Я не думаю, что это наследование TPH, если вы включите учеников и учителей в класс PersonContext.Разве весь смысл TPH не в том, чтобы иметь одну таблицу, таблицу Person?Я бы убрал эти две строки

public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; }

Если вы посмотрите на это пошаговое руководство , особенно в разделе «Добавление типа сущности человека в модель», вы поймете, что я имею в виду.Я не уверен, что это как-то связано с вашей конкретной проблемой, но вы все равно можете это заметить.

1 голос
/ 18 сентября 2011

Я немного переписываю ваш код, он принимает то, что вы хотите:

У вас есть PersonId в качестве первичного ключа и присутствуют все другие ограничения.

public abstract class Person
{
    public int PersonId { get; set; }

    [Required]
    [MaxLength(50)]
    public string FirstName { get; set; }

    [Required]
    [MaxLength(50)]
    public string LastName { get; set; }
}

public class Student : Person
{
    [Column("RegisteredOn")]
    public DateTime RegisteredOnUtc { get; set; }
    public int Age { get; set; }
}

public class Teacher : Person
{
    [Required]
    [MaxLength(50)]
    public string LessonName { get; set; }
}

public class PersonMap : EntityTypeConfiguration<Person>
{
    public PersonMap()
    {
        Map<Student>(x => x.Requires("IsStudent").HasValue(true));
        Map<Teacher>(x => x.Requires("IsStudent").HasValue(false));
    }
}

public class PersonContext : DbContext
{
    public DbSet<Person> Persons { get; set; }
    public DbSet<Student> Students { get; set; }
    public DbSet<Teacher> Teachers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
        modelBuilder.Configurations.Add(new PersonMap());
    }

    public void Detach(object entity)
    {
        var objectContext = ((IObjectContextAdapter)this).ObjectContext;
        objectContext.Detach(entity);
    }
}

Ваша БД выглядит так:

enter image description here

добавить код для теста

    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Data.Entity.ModelConfiguration;
    using System.Data.Objects;

    namespace ConsoleApplication5
    {
        public abstract class Person
        {
            public int PersonId { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        public class Student : Person
        {
            public DateTime RegisteredOnUtc { get; set; }
            public int Age { get; set; }
        }

        public class Teacher : Person
        {
            public string LessonName { get; set; }
        }

        public class PersonMap : EntityTypeConfiguration<Person>
        {
            public PersonMap()
                : base()
            {

                this.HasKey(t => t.PersonId);

                this.Property(t => t.FirstName)
                    .IsRequired()
                    .HasMaxLength(50);

                this.Property(t => t.LastName)
                    .IsRequired()
                    .HasMaxLength(50);

                this.ToTable("Persons");

                this.Property(t => t.PersonId).HasColumnName("PersonId");
                this.Property(t => t.FirstName).HasColumnName("FirstName");
                this.Property(t => t.LastName).HasColumnName("LastName");

                this.Map<Student>(x => x.Requires("IsStudent").HasValue(true));
                this.Map<Teacher>(x => x.Requires("IsStudent").HasValue(false));
            }
        }

        public class StudentMap : EntityTypeConfiguration<Student>
        {
            public StudentMap()
                : base()
            {

                this.Property(t => t.RegisteredOnUtc).HasColumnName("RegisteredOn");
            }
        }

        public class TeacherMap : EntityTypeConfiguration<Teacher>
        {
            public TeacherMap()
                : base()
            {

                this.Property(t => t.LessonName)
                    .IsRequired()
                    .HasMaxLength(50);

                this.Property(t => t.LessonName).HasColumnName("Lesson");
            }
        }

        public class PersonContext : DbContext
        {

            public ObjectContext ObjectContext
            {
                get
                {
                    return ((IObjectContextAdapter)this).ObjectContext;
                }
            }

            public DbSet<Person> Persons { get; set; }
            public DbSet<Student> Students { get; set; }
            public DbSet<Teacher> Teachers { get; set; }

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
                modelBuilder.Configurations.Add(new PersonMap());
                modelBuilder.Configurations.Add(new StudentMap());
                modelBuilder.Configurations.Add(new TeacherMap());
            }

            public void Detach(object entity)
            {
                var objectContext = ((IObjectContextAdapter)this).ObjectContext;
                objectContext.Detach(entity);
            }
        }

        public class Program
        {
            static void Main()
            {
                var personContext = new PersonContext();
                personContext.Database.Delete();
                personContext.Database.Create();
            }
        }
    }
...