假设我们有一个域类
public class Incident
{
[Key]
public virtual int IncidentId { get; set; }
[Display(Name = "Parent Incident")]
public virtual Incident ParentIncident { get; set; }
[Display(Name = "Related Claim")]
public virtual Incident ClaimIncident { get; set; }
}
为了简单起见,省略了其他属性。
当我刚刚ParentIncident
就位后,一切正常。现在我已经添加了ClaimIncident
到班级。我正在尝试使用 Entity Framework 4.3(预发布)更新我的数据库Migrations
选项,但我收到错误,EF 不知道如何将事件映射到事件。
为什么每个类允许引用同一个类实例一次,而当我引入第二个类时,它突然不知道如何引用它?我怎样才能纠正模型类?
这就是我认为正在发生的事情。当您只有 ParentIncident Code First 时,按照惯例将其映射为自引用一对多单向独立关联的一端。这里有很多行话——让我解释一下:
- 自引用:从问题中可以明显看出,事件实体位于关系的两端。
- 一对多:每个事件都有一个父事件,一个事件可以是多个事件的父事件。
- 单向:有从事件到其父事件 (ParentIncident) 的导航属性,但没有子事件的反向集合导航属性。
- 独立关联:由于类中没有外键属性,EF 在数据库中创建一个 FK 列(称为 ParentIncident_IncidentId),但它不映射到任何对象属性。
现在,当您添加 ClaimIncident 属性时,这会更改 Code First 尝试映射的方式。它现在创建一个自引用的一对一双向 FK 关联:
- 一对一,因为它看到从事件到事件的两个导航属性,并假设它们是同一关系的两侧。由于两者都不是集合属性,因此关系是一对一的。
- 再次是双向的,因为现在关系的每一端都有一个导航属性。
- FK,因为一对一关系变为 PK 到 PK,并且 EF 始终将其视为 FK 关系,因为 FK(即 PK)已映射。
但 Code First 无法弄清楚这种一对一关系的哪一端应该是主体端,哪一端应该是从属端。有时这确实很重要......所以 Code First 会抛出异常。
好的,所以我将从线程和您的模型中推断出您实际上并不想要这里存在一对一的关系。 (一对一的自引用 PK 到 PK 关系是毫无意义的,因此您可能会认为 Code First 不应该创建它,但 Code First 并不那么聪明。)
所以你把 FK 放进去。发生了两件事。首先,Code First 现在假设这些必须再次是一对多关系。其次,Code First 现在有了 FK 属性的名称,并依次使用该名称来命名数据库中的 FK 列。但该名称与已为独立关联创建的 FK 列不同 — 它不是 ParentIncident_IncidentId。这意味着迁移必须删除此列并创建一个新列...导致数据丢失。
要告诉 Code First 您实际上只需要两个自引用、单向、一对多、独立的关联,请使用以下流畅的映射:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Incident>()
.HasOptional(e => e.ParentIncident)
.WithMany();
modelBuilder.Entity<Incident>()
.HasOptional(e => e.ClaimIncident)
.WithMany();
}
现在迁移应该正确更新您的数据库。现在,必须要说的是,您可能要考虑更改为 FK 关联,在这种情况下,您要么需要在 Migrations 中进行一些数据移动,如果有数据丢失就接受,或者告诉 Code First 继续使用 FK之前生成的列名称。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)