Search code examples
asp.net-mvc-3entity-frameworktable-relationships

EF multiple relationships between entities


I'm using the Code First approach to build the database in this problem. I have the following (partial) entity:

public class Tournament {
    public int TournamentID { get; set; }
    public String Name { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public int? SportID { get; set; }

    public virtual Sport Sport { get; set; }

    public virtual ICollection<Official> Officials { get; set; }
}

In the Official Entity I have this:

public class Official {
    public int OfficialID { get; set; }
    public String Surname { get; set; }
    public String FirstName { get; set; }
    public int? TournamentID { get; set; }

    public virtual Tournament Tournament { get; set; }

    public virtual ICollection<Match> Matches { get; set; }
}

Using some sample data and checking the SQL Server database, this works as I would expect it to. The tournament has a one-to-many relationship with officials.

The problem I'm having is that I would like the tournament to hold the primary key of an official as the head official. So I would add to the Tournament entity:

public int? OfficialID { get; set; } // foreign key to official table
public virtual Official HeadOfficial { get; set; } // navigation property

If I do this I get an attribute OfficialID and HeadOfficial_OfficialID in my Tournament table and I get TournamentID, Tournament_TournamentID and Tournament_TournamentID1 in my Officials table. I realise I now not only have a one-to-many relationship between Tournament and Official (seeing as a tournament can have many officials), but I also have a one-to-one relationship (seeing as a tournament can only have one head official).

How can I fix this problem?


Solution

  • You can fix the problem by giving EF a hint which navigation properties belong together. EF conventions cannot decide this anymore when you have two navigation properties in a class which refer to the same target class:

    public class Tournament {
        public int TournamentID { get; set; }
        //...
    
        public int? OfficialID { get; set; }
        [ForeignKey("OfficialID")]
        public virtual Official HeadOfficial { get; set; }
    
        [InverseProperty("Tournament")] // the navigation property in Official class
        public virtual ICollection<Official> Officials { get; set; }
    }
    

    It's also possible with Fluent API if you prefer that:

    modelBuilder.Entity<Tournament>()
        .HasOptional(t => t.HeadOfficial)
        .WithMany()
        .HasForeignKey(t => t.OfficialID);
    
    modelBuilder.Entity<Tournament>()
        .HasMany(t => t.Officials)
        .WithOptional(o => o.Tournament)
        .HasForeignKey(o => o.TournamentID);