Определение нескольких внешних ключей для одной и той же таблицы в корневом коде Entity First

У меня есть два объекта в моем приложении MVC, и я заполнил базу данных с помощью подхода Entity Framework 6 Code First. В студенческой организации есть два идентификатора города; один из них для BirthCity, другой для WorkCity. Когда я определяю внешние ключи, как указано выше, после миграции создается дополнительный столбец с именем City_ID в таблице Student. Id там ошибка или как определить эти FK? Спасибо заранее.

Студент:

public class Student
{
    public int ID { get; set; }

    public string Name { get; set; }

    public string Surname { get; set; }

    public int BirthCityID { get; set; }

    public int LivingCityID { get; set; }


    [ForeignKey("BirthCityID")]
    public virtual City BirthCity { get; set; }

    [ForeignKey("LivingCityID")]
    public virtual City LivingCity { get; set; }
}


Город:

public class City
{
    public int ID { get; set; }

    public string CityName { get; set; }


    public virtual ICollection<Student> Students { get; set; }
}

Ответ 1

Чтобы достичь того, что вы хотите, вам нужно предоставить некоторую дополнительную конфигурацию. Код Первое соглашение может идентифицировать двунаправленные отношения, но не тогда, когда есть несколько двунаправленных отношений между двумя объектами. Вы можете добавить конфигурацию (используя Аннотации данных или Fluent API), чтобы представить это информацию строителю модели. С аннотациями данных вы будете использовать аннотацию называемый InverseProperty. С Fluent API вы будете использовать комбинацию методов Has/With, чтобы указать правильные концы этих отношений.

Использование Аннотации данных может быть таким:

public class Student
{
  public int ID { get; set; }

  public string Name { get; set; }

  public string Surname { get; set; }

  public int BirthCityID { get; set; }

  public int LivingCityID { get; set; }


  [ForeignKey("BirthCityID")]
  [InverseProperty("Students")]
  public virtual City BirthCity { get; set; }

  [ForeignKey("LivingCityID")]
  public virtual City LivingCity { get; set; }
}

Таким образом вы явно указываете, что хотите связать свойство навигации BirthCity с атрибутом навигации Students в другом конце отношения.

Использование Fluent Api может быть таким:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     modelBuilder.Entity<Student>().HasRequired(m => m.BirthCity)
                                 .WithMany(m => m.Students).HasForeignKey(m=>m.BirthCityId);
     modelBuilder.Entity<Student>().HasRequired(m => m.LivingCity)
                                 .WithMany().HasForeignKey(m=>m.LivingCityId);
}

С помощью этого последнего решения вам не нужно использовать какой-либо аттрибут.

Теперь предложение @ChristPratt in имеет набор Student в вашем классе City для каждой взаимосвязи. Если вы это сделаете, то конфигурации с использованием Аннотации данных могут быть следующими:

public class Student
{
  public int ID { get; set; }

  public string Name { get; set; }

  public string Surname { get; set; }

  public int BirthCityID { get; set; }

  public int LivingCityID { get; set; }


  [ForeignKey("BirthCityID")]
  [InverseProperty("BirthCityStudents")]
  public virtual City BirthCity { get; set; }

  [ForeignKey("LivingCityID")]
  [InverseProperty("LivingCityStudents")]
  public virtual City LivingCity { get; set; }
}

Или используя Fluent Api, следуя той же идее:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     modelBuilder.Entity<Student>().HasRequired(m => m.BirthCity)
               .WithMany(m => m.BirthCityStudents).HasForeignKey(m=>m.BirthCityId);
     modelBuilder.Entity<Student>().HasRequired(m => m.LivingCity)
               .WithMany(m => m.LivingCityStudents).HasForeignKey(m=>m.LivingCityId);
}

Ответ 2

Sheesh. Это был долгий день. На самом деле на самом деле очень большая, вопиющая проблема с вашим кодом, который я полностью пропустил, когда комментировал.

Проблема заключается в том, что вы используете одну коллекцию студентов на City. Что на самом деле происходит здесь, так это то, что EF не может решить, какой внешний ключ он должен на самом деле отображать в этой коллекции, поэтому он создает другой внешний ключ для отслеживания этих отношений. Затем, по сути, у вас нет свойств навигации для коллекций студентов, полученных из BirthCity и LivingCity.

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

public class City
{
    ...

    public virtual ICollection<Student> BirthCityStudents { get; set; }
    public virtual ICollection<Student> LivingCityStudents { get; set; }
}

Затем для Student:

public class Student
{
    ...

    public class StudentMapping : EntityTypeConfiguration<Student>
    {
        public StudentMapping()
        {
            HasRequired(m => m.BirthCity).WithMany(m => m.BirthCityStudents);
            HasRequired(m => m.LivingCity).WithMany(m => m.LivingCityStudents);
        }
    }
}

И, наконец, в вашем контексте:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new Student.StudentMapping());
}