【问题标题】:EF Code First migrations: Table Per Hierarchy BugEF Code First 迁移:每个层次结构错误的表
【发布时间】:2013-04-29 08:52:45
【问题描述】:
  • 通常我们可能需要对现有数据库使用 Entity Framework Code First。
    • 现有数据库可能具有允许“按层次结构表”继承的结构。
  • 或者我们可以从如下所示的对象模型开始:

public partial class Person {
    public int Id { get; set; }
    public string Discriminator { get; set; }
    public string Name { get; set; }
    public Nullable<int> StudentTypeId { get; set; }
    public virtual StudentType StudentType { get; set; }
}

public partial class StudentType {
    public StudentType() {
        this.People = new List<Person>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Person> People { get; set; }
}

我们创建初始迁移:

enable-migrations
add-migration Initial

迁移看起来像:

public override void Up()
{
    CreateTable(
        "dbo.Person",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                Discriminator = c.String(maxLength: 4000),
                Name = c.String(maxLength: 4000),
                StudentTypeId = c.Int(),
            })
        .PrimaryKey(t => t.Id)
        .ForeignKey("dbo.StudentType", t => t.StudentTypeId)
        .Index(t => t.StudentTypeId);

    CreateTable(
        "dbo.StudentType",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                Name = c.String(maxLength: 4000),
            })
        .PrimaryKey(t => t.Id);           
}

要生成这个数据库,我们:

update-database

这会产生一个我们可以像这样生成的数据库。

create table Person(
  Id int Identity(1,1) Primary key,
  Discriminator nvarchar(4000) null,
  StudentTypeId int null,
)

create table StudentType(
  Id int Identity(1,1) Primary key,
  Name nvarchar(4000) not null
)

alter table Person 
add constraint StudentType_Person
foreign key (StudentTypeId)
references StudentType(Id)

我们在生产中使用这个数据库一段时间...

现在我们要添加不同于普通人的学生的概念。

Entity Framework 提供了三种表示继承的方法。在这种情况下,我们选择“按层次结构表”方法。

为了实现这种方法,我们将 POCO 修改如下:

public class Person {
   public int Id { Get; set; }
   public string Name { get; set }
}

public class Student : Person {
  public virtual StudentType StudentType { get; set; }
  public int? StudentTypeId { get; set; }
}

public class StudentType {
    public StudentType() {
        Students = new List<Student>();
    }

    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

注意:

  • 只有学生可以访问StudentType 属性。
  • 我们没有在 Person 类中指定 Discriminator 属性。 EF Code First 看到 Student 继承自 Person 并会为我们在 Person 表中添加一个 Discriminator 列。

现在我们运行:

add-migration Person_TPH

我们得到了这个意想不到的输出。

public override void Up()
{
    AddColumn("dbo.Person", "StudentType_Id", c => c.Int());
    AlterColumn("dbo.Person", "Discriminator", c => c.String(nullable: false, maxLength: 128));
    AddForeignKey("dbo.Person", "StudentType_Id", "dbo.StudentType", "Id");
    CreateIndex("dbo.Person", "StudentType_Id");
}

不应添加StudentType_Id 列或索引。

我们可以通过添加 'StudentMap' 类来明确:

public class StudentMap : EntityTypeConfiguration<Student> {
    public StudentMap() {
        this.HasOptional(x => x.StudentType)
            .WithMany()
            .HasForeignKey(x => x.StudentTypeId);
    }
}

但没有快乐..

确实,如果我们删除数据库和所有迁移。 然后针对我们得到的新模型运行add-migration Initial

public override void Up()
{
    CreateTable(
        "dbo.Person",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                Name = c.String(maxLength: 4000),
                StudentTypeId = c.Int(),
                Discriminator = c.String(nullable: false, maxLength: 128),
            })
        .PrimaryKey(t => t.Id)
        .ForeignKey("dbo.StudentType", t => t.StudentTypeId)
        .Index(t => t.StudentTypeId);

    CreateTable(
        "dbo.StudentType",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
                Name = c.String(nullable: false, maxLength: 100),
            })
        .PrimaryKey(t => t.Id);           
}

在这个“正确”版本中,我们看到 EF Code First 迁移按预期使用 StudentTypeId 列。

问题

鉴于数据库已经存在,有没有办法告诉 EF Code First 迁移使用现有的 StudentTypeId 列。

演示问题的 GitHub 存储库在这里:

https://github.com/paulyk/ef_code_first_proof_of_tph_bug.git

Git tags
1_add_migration_Initial
2_add_migration_person_TPH
3_add_studentMap

【问题讨论】:

    标签: entity-framework ef-code-first entity-framework-5


    【解决方案1】:

    我发现有 3 个约定与在类中发现显式外键有关:

    System.Data.Entity.ModelConfiguration.Conventions.NavigationPropertyNameForeignKeyDiscoveryConvention System.Data.Entity.ModelConfiguration.Conventions.PrimaryKeyNameForeignKeyDiscoveryConvention System.Data.Entity.ModelConfiguration.Conventions.TypeNameForeignKeyDiscoveryConvention

    PrimaryKeyNameForeignKeyDiscoveryConvention 在这里没有帮助,因为 StudentType 上的主键只是 Id。不过,其他两个都将在 StudentTypeId 上匹配,所以只要您不删除这两个,约定应该会选择它。

    不过,根据这个问题 (Foreign key navigation property naming convention alternatives),您也可以将 [ForeignKey("StudentTypeId")] 添加到 Student 上的 StudentType 属性和 [InverseProperty("StudentType")]Students 上的 Students 属性@。

    希望对您有所帮助。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多