Andrew
Andrew

Reputation: 11338

Tricky Entity Framework one to one relationship

I have an app which records entries into different events of tennis tournaments. It also records who the winner was of each event

The 2 classes in question are:

public class Event {
  public int EventId { get; set; }
  public string EventName { get; set; }
  public virtual ICollection<Entry> Entries { get; set; }
  public int? WinningEntryId { get; set; }

  [ForeignKey("WinningEntryId")]
  public virtual Entry WinningEntry { get; set; }
}

public class Entry {
  public int EntryId { get; set; }
  public int EventId { get; set; }

  [ForeignKey("EventId")]
  public virtual Event Event { get; set; }
}

Note that the Event.WinningEntryId column is nullable as I don't want to have to specify the winner as the tournament may still be in progress.

Now, the problem is that when I run the Update-Database command, it generates the following tables:

Entry
 - EntryId
 - EventId
 - Event_EventId

Event
 - EventId
 - WinningEntryId

Why is EF generating the Event_EventId column in the Event table? I simply want the Event.WinningEntryId column to point to the Entry.EntryId column in a foreign key relationship.

I must be doing this wrong somehow. Anybody know how I can accomplish this?

Upvotes: 4

Views: 1996

Answers (2)

Komengem
Komengem

Reputation: 3774

The marked answer accomplishes what you need to do but the real reason as to why you were getting Event_EventId in your table is because of this:

public virtual ICollection<Entry> Entries { get; set; }

Noted in your Event entity. Which simply means that an Event is a collection of similar Entries. And by that logic, creates a one-to-many relationship between Event and Entry.

-Event has many Entries

-Entry belongs to one Event

Therefore, Each Entry must have foreign key Event_EventId to state which Event the Entry belongs to.

Upvotes: 1

devdigital
devdigital

Reputation: 34369

Assuming that your navigation property:

public virtual Entry WinningEntryId { get; set; }

is actually called WinningEntry:

public virtual Entry WinningEntry { get; set; }

then actually it looks like you're modelling a one-to-many relationship, not a one-to-one. An event can have many entries, and an entry can belong to one event? It's just that one of those entries will be marked as the winning entry.

I would consider not using data annotations, and sticking with the fluent API for a) management of all of your configuration in a central place and b) not mixing persistence concerns with your domain objects.

In which case, you could configure your mappings using the fluent API as such:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{     
    modelBuilder.Entity<Event>()
       .HasOptional(ev => ev.WinningEntry)
       .WithMany()
       .HasForeignKey(ev => ev.WinningEntryId)
       .WillCascadeOnDelete(false);

    modelBuilder.Entity<Entry>()
        .HasRequired(en => en.Event)
        .WithMany(ev => ev.Entries)
        .HasForeignKey(en => en.EventId);
}

This will model the relationship with:

Events
    EventId (PK)
    EventName
    WinningEventId (FK, null)

Entries
    EntryId (PK)
    EventId (FK, not null)

Upvotes: 5

Related Questions