EF 不会根据我的模型更新表
EF won't update tables based on my model
起初我创建了一个只包含基本属性的 Person 模型:
[Table("SGDB_Persons")]
public class Person {
public int Id { get; set; }
[Required]
public string Firstname { get; set; }
[Required]
public string Lastname { get; set; }
[Required]
public Department Department { get; set; }
[Required]
public SourceType SourceType { get; set; }
在我发现我遗漏了一些东西后,我添加了一个新的 PersonData 属性:
[Required]
public PersonData PersonData { get; set; }
不幸的是,EF 根本不会更新数据库 - 最初包含 Person 类型对象的 PersonData 已更新,因此不再有 Person 属性。另一方面,EF 不会为 PersonData_Id.
创建新列
此外,ID 列不会自动递增(所有其他 table 的 Id 列都会自动递增)。令我困惑的是以下在我的 Person table:
中创建的 Constraing
CONSTRAINT [FK_dbo.SGDB_Persons_dbo.SGDB_PersonData_Id] FOREIGN KEY ([Id]) REFERENCES [dbo].[SGDB_PersonData] ([Id])
我什么都试过了(至少我是这么认为的)。我手动删除了所有 tables / 整个数据库,重新安装了 EF,执行了手动迁移,但似乎没有任何效果。
我认为是这个问题导致我无法使用以下代码为我的数据库播种:
protected override void Seed(PersonContext context) {
base.Seed(context);
var dep = new DepartmentContext().Departments.First();
var status = new Status("Test");
var persondata = new PersonData(status);
context.Status.Add(status);
context.PersonData.Add(persondata);
for (int i = 0; i < 10; i++) {
var person = new Person {
Firstname = $"TestPersonFirstname{i}",
Lastname = $"TestPersonLastname{i}",
SourceType = COM.SourceType.Manual,
Department = dep,
PersonData = persondata
};
context.Persons.Add(person);
}
context.SaveChanges();
}
每次执行此代码时,我都会收到异常:
The member with identity 'SGDB.DAL.Contexts.Person_Department' does not exist in the metadata collection. Parameter name: identity.
我不知道这两个问题是否与同一个问题有关,但都需要解决:)
提前致谢!
更新 1
我的解决方案分为几个不同的项目:
BLL、DAL、COM、UI
DataContexts 位于 DAL 项目中,模型位于 COM 项目中。
部门模型:
[Table("SGDB_Departments")]
public class Department {
public int Id { get; set; }
[Required]
public string Costcenter { get; set; }
[Required]
public string Abbreviation { get; set; }
public string Description { get; set; }
public string FullDepartmentName {
get {
return $@"{Division.Abbreviation}\{Abbreviation}";
}
}
[Required]
public virtual Division Division { get; set; }
}
个人数据模型:
[Table("SGDB_PersonData")]
public class PersonData {
public PersonData(Status status) {
Status = status;
}
public int Id { get; set; }
public DateTime Limit { get; set; }
public Person Responsible { get; set; }
[Required]
public Status Status { get; set; }
}
人 table(如您所见)有一个 Department_Id 列(EF 自动插入)。
澄清
Person 对象包含一个 PersonData 对象作为此 Person 的附加信息。一个人可能/可能没有一个负责人(所以 PersonData.Responsible 不是父人的导航 属性)。
另外,如果可能的话,我不想在 PersonData table.
中有一个外键
据我所知,我必须修改
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithRequiredPrincipal(e => e.Responsible)
.WillCascadeOnDelete(true);
至
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithMany()
.WillCascadeOnDelete(true);
我会试试这个,如果它解决了我的问题,我会报告。
更新 2
The member with identity 'SGDB.DAL.Contexts.Person_Department' does not exist in the metadata collection.
您的模型定义了 Person
和 PersonData
之间的 one-to-one
关系,后者是必需的,前者是可选的。 EF 始终将 one-to-one
关系的必需部分用作 principal,并将可选部分用作 dependent。因此它认为 PersonaData
是主体,Person
- 依赖并反映在数据库 table 设计中。
你需要相反的,而且双方都需要。当两侧都是必需或可选时,EF 无法自动派生 principal/dependent 侧并且无法通过数据注释(属性)指定它,因此您需要一个流畅的 API 设置。
覆盖您的 DbContext OnModelCreating
并添加如下内容:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithRequiredPrincipal(e => e.Responsible)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
它的作用是告诉EF,Person->PersonData
关系的两边都是必须的,Person
是主体。这应该再次使您的 Person.Id
列自动递增,并且应该解决问题的人员数据部分。
我注意到的另一件事是这一行:
var dep = new DepartmentContext().Departments.First();
而同一过程的所有其他部分都使用名为 context
的变量。这个 might/might 不是问题,检查一下就可以了。
更新: 从更新问题中的说明可以看出,Person
和 [=] 之间有 两个 关系15=],所以你需要像这样为它们中的每一个单独配置:
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithRequiredPrincipal()
.WillCascadeOnDelete(true);
modelBuilder.Entity<PersonData>()
.HasOptional(e => e.Responsible)
.WithOptionalDependent() // or WithMany()
.WillCascadeOnDelete(false);
请注意,在 PersonData
table 中没有办法不引入额外的 FK 列。它需要表示 Responsible
关系,因此您最终会得到一个名为 Responsible_Id
.
的 table 列
起初我创建了一个只包含基本属性的 Person 模型:
[Table("SGDB_Persons")]
public class Person {
public int Id { get; set; }
[Required]
public string Firstname { get; set; }
[Required]
public string Lastname { get; set; }
[Required]
public Department Department { get; set; }
[Required]
public SourceType SourceType { get; set; }
在我发现我遗漏了一些东西后,我添加了一个新的 PersonData 属性:
[Required]
public PersonData PersonData { get; set; }
不幸的是,EF 根本不会更新数据库 - 最初包含 Person 类型对象的 PersonData 已更新,因此不再有 Person 属性。另一方面,EF 不会为 PersonData_Id.
创建新列此外,ID 列不会自动递增(所有其他 table 的 Id 列都会自动递增)。令我困惑的是以下在我的 Person table:
中创建的 ConstraingCONSTRAINT [FK_dbo.SGDB_Persons_dbo.SGDB_PersonData_Id] FOREIGN KEY ([Id]) REFERENCES [dbo].[SGDB_PersonData] ([Id])
我什么都试过了(至少我是这么认为的)。我手动删除了所有 tables / 整个数据库,重新安装了 EF,执行了手动迁移,但似乎没有任何效果。
我认为是这个问题导致我无法使用以下代码为我的数据库播种:
protected override void Seed(PersonContext context) {
base.Seed(context);
var dep = new DepartmentContext().Departments.First();
var status = new Status("Test");
var persondata = new PersonData(status);
context.Status.Add(status);
context.PersonData.Add(persondata);
for (int i = 0; i < 10; i++) {
var person = new Person {
Firstname = $"TestPersonFirstname{i}",
Lastname = $"TestPersonLastname{i}",
SourceType = COM.SourceType.Manual,
Department = dep,
PersonData = persondata
};
context.Persons.Add(person);
}
context.SaveChanges();
}
每次执行此代码时,我都会收到异常:
The member with identity 'SGDB.DAL.Contexts.Person_Department' does not exist in the metadata collection. Parameter name: identity.
我不知道这两个问题是否与同一个问题有关,但都需要解决:)
提前致谢!
更新 1
我的解决方案分为几个不同的项目:
BLL、DAL、COM、UI
DataContexts 位于 DAL 项目中,模型位于 COM 项目中。
部门模型:
[Table("SGDB_Departments")]
public class Department {
public int Id { get; set; }
[Required]
public string Costcenter { get; set; }
[Required]
public string Abbreviation { get; set; }
public string Description { get; set; }
public string FullDepartmentName {
get {
return $@"{Division.Abbreviation}\{Abbreviation}";
}
}
[Required]
public virtual Division Division { get; set; }
}
个人数据模型:
[Table("SGDB_PersonData")]
public class PersonData {
public PersonData(Status status) {
Status = status;
}
public int Id { get; set; }
public DateTime Limit { get; set; }
public Person Responsible { get; set; }
[Required]
public Status Status { get; set; }
}
人 table(如您所见)有一个 Department_Id 列(EF 自动插入)。
澄清
Person 对象包含一个 PersonData 对象作为此 Person 的附加信息。一个人可能/可能没有一个负责人(所以 PersonData.Responsible 不是父人的导航 属性)。 另外,如果可能的话,我不想在 PersonData table.
中有一个外键据我所知,我必须修改
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithRequiredPrincipal(e => e.Responsible)
.WillCascadeOnDelete(true);
至
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithMany()
.WillCascadeOnDelete(true);
我会试试这个,如果它解决了我的问题,我会报告。
更新 2
The member with identity 'SGDB.DAL.Contexts.Person_Department' does not exist in the metadata collection.
您的模型定义了 Person
和 PersonData
之间的 one-to-one
关系,后者是必需的,前者是可选的。 EF 始终将 one-to-one
关系的必需部分用作 principal,并将可选部分用作 dependent。因此它认为 PersonaData
是主体,Person
- 依赖并反映在数据库 table 设计中。
你需要相反的,而且双方都需要。当两侧都是必需或可选时,EF 无法自动派生 principal/dependent 侧并且无法通过数据注释(属性)指定它,因此您需要一个流畅的 API 设置。
覆盖您的 DbContext OnModelCreating
并添加如下内容:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithRequiredPrincipal(e => e.Responsible)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
它的作用是告诉EF,Person->PersonData
关系的两边都是必须的,Person
是主体。这应该再次使您的 Person.Id
列自动递增,并且应该解决问题的人员数据部分。
我注意到的另一件事是这一行:
var dep = new DepartmentContext().Departments.First();
而同一过程的所有其他部分都使用名为 context
的变量。这个 might/might 不是问题,检查一下就可以了。
更新: 从更新问题中的说明可以看出,Person
和 [=] 之间有 两个 关系15=],所以你需要像这样为它们中的每一个单独配置:
modelBuilder.Entity<Person>()
.HasRequired(e => e.PersonData)
.WithRequiredPrincipal()
.WillCascadeOnDelete(true);
modelBuilder.Entity<PersonData>()
.HasOptional(e => e.Responsible)
.WithOptionalDependent() // or WithMany()
.WillCascadeOnDelete(false);
请注意,在 PersonData
table 中没有办法不引入额外的 FK 列。它需要表示 Responsible
关系,因此您最终会得到一个名为 Responsible_Id
.