Matador1006
Matador1006

Reputation: 43

Entity Framework Code First - Many-to-Many Foreign Key Problem

I'm playing around with EF Code First and need some help.

A User can create many Posts.
A User can recommend many Posts
A Post can have many user Recommendations.

Given this code:

public class User
{
    public int UserID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
    public virtual ICollection<Post> Recommendations { get; set; }
}


public class Post
{
    public int PostID { get; set; }
    public int UserID { get; set; }
    public virtual User User { get; set; }
    public virtual ICollection<User> RecommendingUsers { get; set; }
}

modelBuilder.Entity<Post>()
.HasMany(x => x.RecommendingUsers)
.WithMany(x => x.Recommendations)
.Map(x => x.MapLeftKey("PostID")
    .MapRightKey("UserID")
    .ToTable("Recommendations"));

I end up with an extra "User_UserID" column in the Post table, which it's using for the foreign key:

PostID (PK, int, not null)
UserID (int, not null)
User_UserID(FK, int, null)

Why isn't it using UserID as the foreign key?

Upvotes: 4

Views: 3598

Answers (1)

Chris Moschini
Chris Moschini

Reputation: 37947

I had the same issue and found two things:

  1. The conventions it's using to map the column names are names like User_UserID and User_ID, not UserID. Solutions:
    1. You can vary the conventions it's using. I'm not clear on whether this is possible in EF 4.1 - Scott Gu has a post lamenting that it is not, but I can see a Conventions property hanging off of the ModelBuilder class... with only one method... Add().
    2. You can set the foreign key name explicitly (see below).
  2. I had cases where I had actually fixed it per suggestions on StackOverflow but the cached DbModel meant it still appeared broken until I actually closed Cassini and forced the dev webserver to restart entirely.

Unfortunately because you're not using the naming conventions the framework assumes, you're going to have to keep using the ForeignKey attribute all over your classes in order to get everything to tie together correctly, or it will keep mapping to the wrong column name.

Setting the Foreign Key name looks like:

[ForeignKey("UserID")]
public virtual User User { get; set; }

This explicitly tells the framework to use UserID instead of User_UserID

In Many-to-Many cases, you need to both use the above Map call, and apply the ForeignKey attribute on both sides.

This solved it for me.

I see now why Scott lamented leaving Conventions out - this really burns when you're trying to put things together on an existing database.

Upvotes: 1

Related Questions