- 通常我們可能需要使用實體框架代碼先用現有的數據庫。
- 現有的數據庫可具有一種結構的允許「表每層次結構」繼承。
- 或者我們可以用一個對象模型,看起來像開始:
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; }
}
我們創建初始遷移:EF的Code First遷移:表每一個分層的Bug
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)
我們在生產中使用這個數據庫了一會兒......
現在我們想補充一點,從只是普通人不同學生的概念。
實體框架爲代表的繼承三種方法。在這種情況下,我們選擇「每個層次表」方法。
爲了實現這個方法,我們修改我們的波蘇斯如下:
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代碼第一次看到從Person
Student
繼承和會Discriminator
列添加到Person表我們。
現在我們運行:
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代碼第一次遷移使用StudentTypeId
列如預期。
問題
鑑於該數據庫已經存在,有沒有辦法告訴EF代碼優先遷移到使用現有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