Code First 的 EF 4.1 中的 TPH 继承映射问题

发布于 2024-12-05 08:18:45 字数 3185 浏览 0 评论 0原文

我的 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' 不是类型 < 上声明的属性代码>“学生”。使用 Ignore 方法或 NotMappedAttribute 数据注释验证该属性是否未从模型中显式排除。确保它是一个有效的原始属性。

如果删除 this.HasKey(t => t.PersonId); StudentTeacher,将抛出此错误:

字典中不存在给定的键。

你有吗有什么想法可以解决这个问题吗?谢谢。

I have these classes in my ASP.NET MVC app:

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

But, when I run the app, get this error:

The property 'PersonId' is not a declared property on type 'Student'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property.

And if remove this.HasKey(t => t.PersonId); from the Student and Teacher, this error will be thrown:

The given key was not present in the dictionary.

Have you any idea to resolve this please? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

没有心的人 2024-12-12 08:18:45

您是否尝试从 StudentMap 和 TeacherMap 中删除这两行?

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

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

我复制了你的代码并在没有这些行的情况下运行它,它工作得很好。

Did you try removing both of these lines from StudentMap and TeacherMap?

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

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

I copied your code and ran it without these lines and it worked just fine.

煞人兵器 2024-12-12 08:18:45

我很少重写你的代码,它需要你想要的:

你有 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);
    }
}

您的数据库如下所示:

在此处输入图像描述

添加测试代码

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

I little rewrite your code, it takes what you want:

You have the PersonId as primary key
and all other limits are present.

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

Your DB looks like:

enter image description here

add code for test

    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();
            }
        }
    }
夜光 2024-12-12 08:18:45

如果您将 Students 和 Teachers 包含在 PersonContext 类中,我认为这不是 TPH 继承。 TPH 的全部意义不就是只有一张表(Person 表)吗? 我会删除这两行

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

如果您查看 本演练,特别是“将人员实体类型添加到模型”部分,您会明白我的意思。我不确定这是否与您的特定问题有很大关系,但无论如何您可能需要注意它。

I don't think it's TPH inheritance if you include the Students and Teachers in the PersonContext class. Isn't the whole point of TPH to just have one table, the Person table? I'd remove these two lines

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

If you look at this walkthrough, particularly the 'Adding the Person Entity Type to the Model' section you'll see what I mean. I'm not sure if this has much to do with your particular problem but you might want to note it anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文