Entity Framework Code First - проблема внешнего ключа «многие ко многим» - PullRequest
4 голосов
/ 12 мая 2011

Я играю с EF Code First и мне нужна помощь.

Пользователь может создавать много сообщений.Пользователь может рекомендовать много сообщенийСообщение может иметь много пользовательских рекомендаций.

С учетом этого кода:

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"));

Я получаю дополнительный столбец "User_UserID" в таблице Post, который используется для внешнего ключа:

PostID (ПК, инт, не ноль)UserID (int, не null)User_UserID (FK, int, null)

Почему он не использует ID пользователя в качестве внешнего ключа?

1 Ответ

1 голос
/ 17 мая 2011

У меня была такая же проблема, и я нашел две вещи:

  1. Соглашения, которые используются для сопоставления имен столбцов, - это имена, такие как User_UserID и User_ID, а не UserID. Решения:
    1. Вы можете варьировать соглашения, которые он использует. Мне не ясно, возможно ли это в EF 4.1 - у Скотта Гу есть пост, жалующийся на то, что это не так, но я могу видеть свойство Conventions, свисающее с класса ModelBuilder ... только с одним методом ... Add ( ).
    2. Вы можете явно указать имя внешнего ключа (см. Ниже).
  2. У меня были случаи, когда я действительно исправлял это в соответствии с предложениями в StackOverflow, но кэшированная DbModel означала, что он все еще оставался неработающим, пока я фактически не закрыл Cassini и не заставил веб-сервер dev полностью перезапуститься.

К сожалению, поскольку вы не используете соглашения об именах, которые предполагает фреймворк, вам придется продолжать использовать атрибут ForeignKey во всех ваших классах, чтобы все связывалось правильно, или он будет продолжать сопоставляться с неверное имя столбца.

Установка имени внешнего ключа выглядит следующим образом:

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

Это явно указывает платформе на использование UserID вместо User_UserID

В случаях «многие ко многим» вам необходимо использовать вышеупомянутый вызов Map и применить атрибут ForeignKey с обеих сторон.

Это решило это для меня.

Теперь я понимаю, почему Скотт оплакивал отсутствие конвенций - это действительно горит, когда вы пытаетесь собрать вещи в существующую базу данных.

...