- 通常我们可能需要对现有数据库使用 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
物业。 - 我们没有在我们的类中指定
Discriminator
属性。Person
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