1

私は、ASP.NET MVC 5とEntity Framework 6のトップにデータベースファーストアプローチを使用してC#を使用して書かれたアプリケーションを用意しました。Entity Framework 6とHas-Many-Through関係を作成するにはどうすればよいですか?

私はStudentモデル、ClassRoomモデル、および2つの関係を結びつける関係モデルを持っていて、StudentToClassRoomと呼ばれています。

すべての生徒を選択できるようにしたいと思っています。生徒ごとに、ClassRoomの生徒にも関係があるようにしたいと考えています。ここで

は、ここに私のモデル

public class Student 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<ClassRoom> ClassRoomRelations { get; set; } 
} 


public class StudentToClassRoom 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 

    [ForeignKey("Student")] 
    [InverseProperty("Id")] 
    public int StudentId { get; set; } 

    [ForeignKey("ClassRoom")] 
    [InverseProperty("Id")] 
    public int ClassRoomId { get; set; } 

    public virtual Student Student { get; set; } 

    public virtual ClassRoom ClassRoom { get; set; } 
} 

public class ClassRoom 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

ある私は

var students = DbContext.Students.Include(x => x.ClassRoomRelations) 
           .ToList(); 

は、しかし、それは各学生のために私に関係のコレクションを与える試みたものです。しかし、私は各学生のためのClassRoomの情報を得ることができるようにしたいです。だから私は学生とクラスルームの間にハス・マルチ・スルーを作りたいと思っています。最後の結果では、私は実際にClassRoomRelationsを気にしません、私はStudentClassRoomオブジェクトについてのみ気にします。

Entity Frameworkを使用して、生徒のリストと各生徒のすべてのクラスルームのコレクションを取得するにはどうすればよいですか?

+0

あなたの時間を浪費しないでください。 EFはそのような関係をサポートしていません。 –

+0

@IvanStoevありがとう:)同じデータセットを取得するための回避策はありますか? –

+0

暗黙のジャンクションテーブルで 'many-to-many'が実際に必要な場合のみ。既存のデータベースにバインドされている場合( 'StudentToClassRoom'は自動ジャンクションテーブルに適さない)、これは問題でもあります。 –

答えて

1

エンティティ関係のこのタイプをサポートしていません。

しかし、あなたがそう(私は、コードをテストしていない)のように同じ結果を得ることができるかもしれ

var studentRooms = DbContext.StudentToClassRoom 
          .Include(x => x.Student) 
          .Include(x => x.ClassRoom) 
          .GroupBy(x => x.Student) 
          .Select(x => new { 
           Student => x.Key 
           ClassRooms => x.Select(relation => relation.ClassRoom) 
          }) 
          .ToList(); 

あなたは基本的にStudentClassRoomモデルと一緒にすべての関係の結果を選択します。その後、1人の学生を多くのClassRoomに連れて行くために、それらをグループ化します。

私はこれが役に立ちそうです。

+0

ありがとうございました。これは動作します! –

0

なぜ簡単に使いませんか?すでに生徒の教室情報を入手できます。

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

    public string Name { get; set; } 

    public Guid ClassRoomId { get; set; } 

    // public virtual ClassRoom ClassRoom { get; set; } 
} 

public class ClassRoom 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

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

public class StudentToClassRoom 
{ 
    public int Id { get; set; } 

    public Guid StudentId { get; set; } 

    public virtual Student Student { get; set; } 

    public Guid ClassRoomId { get; set; } 

    public virtual ClassRoom ClassRoom { get; set; } 
} 

// var students = DbContext.Students.Include(x => x.ClassRoom).ToList(); 

var mergedRecords = DbContext.StudentToClassRoom 
          .Include(x => x.Student) 
          .Include(x => x.ClassRoom) 
          .ToList() 
+0

私の 'ClassRoom'は' StudentId'プロパティ/カラムを持たないので、私はStudentからClassRoomに直接ナビゲーションプロパティを作成できます。モデル「StudentToClassRoom」は、2つの間の関係を識別できるようにするために必要です。 –

+0

投稿を編集しました。もう一度それをチェックしてください。 –

0

エンティティフレームワークは、多対多のリレーションシップを処理するのに適しています。これは学生だと思うする

EFの方法は、教室があり、教室は生徒を持っています

public class Student 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<ClassRoom> ClassRooms { get; set; } 
} 

public class ClassRoom 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    public string Name { get; set; } 

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

関係テーブルを完全にEFマップでは無視されます。詳しくはthis tutorialをご覧ください。

EDIT:いくつかのクエリ以下
このマップのシナリオを使用する方法を簡素化する:

は、特定の学生のすべてのクラスの部屋のリストを取得します:

var classRoomsOfSpecificStudent = DbContext 
    .Students 
    .First(s => s.Id == studentId) 
    .ClassRooms 
    .ToList(); 

はのリストを取得します。 "a"を含む名前を持つ学生のすべてのクラスルーム。

var classRooms = DbContext 
    .Students 
    .Where(s => s.Name.Contains("a")) 
    .SelectMany(s => s.ClassRooms) 
    .ToList(); 

「a」を含む名前と「2b」を含むクラスルームの名前を持つすべての生徒を取得します。

var students = DbContext 
    .Students 
    .Where(s => s.Name.Contains("a")) 
    .Where(s => s.ClassRooms.Any(c => c.Name.Contains("2b"))) 
    .ToList(); 

私は少し明確にしたいと思います。

+0

私は混乱しています。私の 'ClassRoom'は' StudentId'プロパティ/カラムを持たないので、 'Student'から' ClassRoom'に直接ナビゲーションプロパティを作ることができます。モデル「StudentToClassRoom」は、2つの間の関係を識別できるようにするために必要です。 –

+0

私はいくつかのクエリで答えを編集した、私はこのマップを使用する方法について少し明確になると思う。 –

1

あなたがブリッジテーブルを公開しましたので、あなたが一緒に行くことができます:

var studentRooms = DbContext.StudentToClassRoom 
          .Include(x => x.Student) 
          .Include(x => x.ClassRoom) 
          .ToList(); 

またhere

を参照してください、あなたは本当に[逆]注釈を必要としない - EFは、あなたがリンクしている知っていますIdにFKと一緒に。

EDIT:あなたの学生のモデルを修正する必要があります学生や教室

まず:

public virtual ICollection<StudentToClassRoom> ClassRoomRelations { get; set; } 

明示的に使用したい場合、あなたは

var studentAndRooms = DbContext.Students 
         .Select(s => new 
         { 
         student = s, 
         classrooms = s.ClassRoomRelations.Select(r => r.ClassRoom) 
         }).ToList(); 
+0

これは良いスタートですが、最終結果がstudent.ClassRoomsにアクセスするように、1つのStudentとMany ClassRoomsを選択する方法がありますか? –

+0

編集を参照してください。また、モデルには修正が必要です。 –

+0

ありがとうございました。私は@Jaylenの答えは、このアプローチに非常に似ていると思うが働いた。 –

0

を実行することができますブリッジテーブルでは、一般的に人工的なキーを持っていないはずです。ブリッジテーブルの外部キー列(StudentId、ClassRoomId)はキーである必要があり、余分なキーを持つことは無駄なオーバーヘッドです。 M2M関係全体

および問合せは、次のようになります

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.ComponentModel.DataAnnotations.Schema; 
using System.Data.Entity; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace Ef6Test 
{ 

    public class Student 
    { 
     [Key] 
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
     public int Id { get; set; } 
     public string Name { get; set; } 

     public virtual ICollection<StudentToClassRoom> StudentToClassRoom { get; set; } = new HashSet<StudentToClassRoom>(); 
    } 


    public class StudentToClassRoom 
    { 

     [ForeignKey("Student"), Column(Order = 0), Key()] 
     public int StudentId { get; set; } 

     [ForeignKey("ClassRoom"), Column(Order = 1), Key()] 
     public int ClassRoomId { get; set; } 

     public virtual Student Student { get; set; } 

     public virtual ClassRoom ClassRoom { get; set; } 
    } 

    public class ClassRoom 
    { 
     [Key] 
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

    class Db: DbContext 
    { 

     public DbSet<Student> Students { get; set; } 
     public DbSet<ClassRoom> Classrooms { get; set; } 

     public DbSet<StudentToClassRoom> StudentToClassRoom { get; set; } 

    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Db>()); 

      using (var db = new Db()) 

      { 

       var students = Enumerable.Range(1, 150).Select(i => new Student() { Name = $"Student{i}" }).ToList(); 
       var classRooms = Enumerable.Range(1, 20).Select(i => new ClassRoom() { Name = $"ClassRoom{i}" }).ToList(); 

       var rand = new Random(); 
       foreach(var s in students) 
       { 
        var classRoomId = rand.Next(0, classRooms.Count - 10); 
        s.StudentToClassRoom.Add(new StudentToClassRoom() { Student = s, ClassRoom = classRooms[classRoomId] }); 
        s.StudentToClassRoom.Add(new StudentToClassRoom() { Student = s, ClassRoom = classRooms[classRoomId+1] }); 
        s.StudentToClassRoom.Add(new StudentToClassRoom() { Student = s, ClassRoom = classRooms[classRoomId+2] }); 

       } 

       db.Students.AddRange(students); 
       db.Classrooms.AddRange(classRooms); 
       db.SaveChanges(); 

      } 
      using (var db = new Db()) 
      { 
       db.Configuration.LazyLoadingEnabled = false; 
       var q = db.Students.Include("StudentToClassRoom.ClassRoom"); 

       var results = q.ToList(); 
       Console.WriteLine(q.ToString()); 


       Console.ReadKey(); 
      } 

     } 
    } 
} 
関連する問題