实体框架中的第二个 Self-To-Self 关系
假设我们有一个域类,
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 (PreRelease) Migrations
选项更新我的数据库,但收到错误消息,EF 不知道如何将事件映射到事件。
为什么每个类允许引用同一个类实例一次,而当我引入第二个类实例时,它突然不知道如何引用它?我怎样才能纠正模型类?
Assume we have a domain class
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; }
}
Other properties are omitted for simplicity.
When I had just ParentIncident
in place, everything worked fine. Now I have added ClaimIncident
to the class. I am attempting to update my database using the Entity Framework 4.3 (PreRelease) Migrations
option, but I am getting an error, that EF doesn't know how to map Incident to Incident.
Why referencing the same class instance once is allowed per class, and when I introduce the second one, it suddenly has no clue of how to reference it? And how can I correct the model class?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这就是我认为正在发生的事情。当您只有 ParentIncident Code First 时,按照惯例将其映射为自引用一对多单向独立关联的一端。这里有很多行话——让我解释一下:
现在,当您添加 ClaimIncident 属性时,这会更改 Code First 尝试映射的方式。它现在创建一个自引用的一对一双向 FK 关联:
但 Code First 无法弄清楚这种一对一关系的哪一端应该是主体端,哪一端应该是从属端。有时这确实很重要......所以 Code First 会抛出异常。
好的,所以我将从线程和您的模型中推断出您实际上并不想要这里存在一对一的关系。 (一对一的自引用 PK 到 PK 关系是毫无意义的,因此您可能会认为 Code First 不应该创建它,但 Code First 并不那么聪明。)
因此您将 FK 放入其中。两个事情发生了。首先,Code First 现在假设这些必须再次是一对多关系。其次,Code First 现在有了 FK 属性的名称,并依次使用该名称来命名数据库中的 FK 列。但该名称与已为独立关联创建的 FK 列不同 — 它不是 ParentIncident_IncidentId。这意味着迁移必须删除此列并创建一个新列...导致数据丢失。
要告诉 Code First 您实际上只需要两个自引用、单向、一对多、独立的关联,请使用这种流畅的映射:
现在迁移应该正确更新您的数据库。现在,必须要说的是,您可能要考虑更改为 FK 关联,在这种情况下,您要么需要在 Migrations 中进行一些数据移动,如果有数据丢失就接受,或者告诉 Code First 继续使用 FK之前生成的列名称。
This is what I think is happening. When you only had ParentIncident Code First was mapping this by convention as one end of a self-referencing one-to-many unidirectional independent association. Lots of jargon there--let me explain:
Now, when you add the ClaimIncident property this changes the way Code First tries to map. It now creates a self-referencing one-to-one bidirectional FK association:
But Code First can't figure out which side of this one-to-one relationship should be the principal end, and which should be the dependant end. And this does matter sometimes...so Code First throws.
Okay, so I'm going to infer from the thread and your model that you don't really want a one-to-one relationship here. (A one-to-one self-referencing PK to PK relationship is kind of pointless, so you could argue that Code First shouldn't create it, but Code First isn't that smart.)
So you put the FKs in. Two things happen. First, Code First now assumes that these must be one-to-many relationships again. Second, Code First now has a name for the FK property and in turn uses that name to name the FK column in the database. But that name is not the same as the FK column already created for the independent associated--it's not ParentIncident_IncidentId. This means that Migrations would have to drop this column and create a new one...resulting in data loss.
To tell Code First that you really just want two self-referencing, unidirectional, one-to-many, independent associations, use this fluent mapping:
Now Migrations should correctly update your database. Now, it must be said that you may want to consider changing to FK associations, in which case you either need to do some data motion in Migrations, just accept the data loss if there is any, or tell Code First to keep using the FK column name that it previously generated.