web-dev-qa-db-ja.com

Entity Framework Code Firstの同じテーブルに複数の外部キーを定義する

MVCアプリケーションに2つのエンティティがあり、データベースにEntity Framework 6 Code Firstアプローチを設定しました。 Studentエンティティには2つの都市IDがあります。 1つはBirthCity用、もう1つはWorkingCity用です。上記のように外部キーを定義すると、移行後にStudentテーブルにCity_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; }
}
36
Jack

Code First規則では、双方向の関係を識別できますが、2つのエンティティ間に複数の双方向の関係がある場合は識別できません。構成を追加できます(Data Annotations またはFluent API)を使用して、この情報をモデルビルダーに提示します。データ注釈では、 InverseProperty という注釈を使用します。 Fluent APIでは、Has/Withメソッドの組み合わせを使用して、これらの関係の正しい終了を指定します。

Data Annotationsを使用すると、次のようになります。

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の提案では、各関係のStudentクラスにCityのコレクションがあります。その場合、Data Annotationsを使用した構成は次のようになります。

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);
}
58
octavioccl

シーシュ。長い一日でした。実際、あなたのコードには非常に大きな、明白な問題があります。実際、私がコメントしたときに私は完全に見落としていました。

問題は、Cityで学生の単一のコレクションを使用していることです。ここで実際に行われているのは、EFがそのコレクションを実際にマッピングする外部キーを決定できないため、その関係を追跡するために別の外部キーを作成することです。次に、実質的にBirthCityおよびLivingCityから派生した生徒のコレクションのナビゲーションプロパティがありません。

このためには、流annotationな構成にドロップダウンする必要があります。これは、データ注釈だけを使用して適切に構成する方法がないためです。また、両方の関係を追跡できるように、学生の追加コレクションが必要になります。

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());
}
18
Chris Pratt