Second Self-To-Self relationship in Entity Framework

故事扮演 提交于 2019-12-23 12:59:37

问题


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?


回答1:


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:

  • Self-referencing: as is apprarant from the question, the Indicent entity is at both ends of the relationship.
  • One-to-many: Each Indicent has a single ParentIncident and an Incident can be the parent for many Incidents.
  • Unidirectional: There is a navigation property from the Incident to its parent (ParentIncident) but no reverse collection navigation properties of child incidents.
  • Indpendent Association: Since there is no foreign key property in the class, EF creates an FK column in the database (called ParentIncident_IncidentId) but it isn't mapped to any object property.

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:

  • One-to-one because it sees two navigation properties from Incident to Incident and assumes that these are two sides of the same relationship. Since neither is a collection property, the relationship is one-to-one.
  • Bidirectional again because there is now a nvaigation property on each end of the relationship.
  • FK because the one-to-one relationship becomes PK to PK and EF always treats this as an FK relationship since the FK (which is a PK) is mapped.

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:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Incident>()
        .HasOptional(e => e.ParentIncident)
        .WithMany();

    modelBuilder.Entity<Incident>()
        .HasOptional(e => e.ClaimIncident)
        .WithMany();
}

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.



来源:https://stackoverflow.com/questions/8943984/second-self-to-self-relationship-in-entity-framework

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!