Bidirectional Entity Foreign Key Names in EF Code First

Posted by: Steven Smith, on 23 Sep 2011 | View original | Bookmarked: 0 time(s)

Ran into a small problem today, where I had two classes referring to one another using EF 4.1 Code First.  Lets say I had a class Item and another class ItemHistory.  ItemHistory has a property of type Item that refers to the Item class.  Item, in turn, has an ICollection<ItemHistory> Histories property: 

public class Item
{
  public int Id { get; set; }
  public virtual ICollection<ItemHistory> Histories { get; set; }
}
 
public class ItemHistory
{
  public int Id { get; set; }
  public virtual Item Item { get; set; }
}

In my DbContext OnModelCreating() I have some code like this to set the foreign key names according to the company standard (capitalize ID, no underscores):

modelBuilder.Entity<ItemHistory>()
    .HasRequired(m => m.Item)
    .WithMany()
    .Map(p => p.MapKey("ItemID"));

Likewise, I specified the primary keys like this:

modelBuilder.Entity<Item>().Property(p => p.Id).HasColumnName("ItemID");
modelBuilder.Entity<ItemHistory>().Property(p => p.Id).HasColumnName("ItemHistoryID");

In this way, I can use the C# convention of simply specifying the Id (in PascalCase) but still keep the database police happy with their standards.  All of this is great except that as it stands now when the database is generated, the ItemHistory table has two foreign key columns:

ItemID
Item_Id1

Do you see what the problem is?  I struggled for a bit trying to search for now to name the foreign key in entity framework code first, but of course everything says to either use MapKey() or if you are actually including the column IDs as properties on your entities, then you can use .HasForeignKey() as shown here.  However, what I didnt immediately realize because I wasnt providing it any parameters anywhere else in my code is that .WithMany() takes an (optional) expression.  So, if you want to specify the relationship on the other entity, you do it in .WithMany() like so:

modelBuilder.Entity<ItemHistory>()
                .HasRequired(m => m.Item)
                .WithMany(i => i.Histories)
                .Map(p => p.MapKey("ItemID"));

 

Once thats done, you should have only a single FK column generated in your database, and it should be the correct one (with ID not _Id1 suffix).


Advertisement
Free Agile Project Management Tool from Telerik
TeamPulse Community Edition helps your team effectively capture requirements, manage project plans, assign and track work, and most importantly, be continually connected with each other.
Category: C# | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 418 | Hits: 13

News Categories

.NET | Agile | Ajax | Architecture | ASP.NET | BizTalk | C# | Certification | Data | DataGrid | DataSet | Debugger | DotNetNuke | Events | GridView | IIS | Indigo | JavaScript | Mobile | Mono | Patterns and Practices | Performance | Podcast | Refactor | Regex | Security | Sharepoint | Silverlight | Smart Client Applications | Software | SQL | VB.NET | Visual Studio | W3 | WCF | WinFx | WPF | WSE | XAML | XLinq | XML | XSD