2017-07-17 7 views
1

私はテーブルの教師とテーブルの学生がいます。テーブル 'teacher'の各レコードはテーブル 'student'に複数のレコードを持ちます。ここに私のモデルクラスは、ここで選択した新しいステートメントですべてのレコードを返すLinqクエリ

public class Test 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public List<StudentsDTO> Students{ get; set; } 
} 

は私のLINQクエリは、レコード

 var st = (from tt in context.Teachers 
            join ss in context.Students 
            on tt.ID equals ss.teacherID 
            where tt.TypeID == 2 
            select new Test 
            { 
             Id = tt.ID, 
             Text = tt.Text, 
             Students= new List<StudentsDTO>() 
             { 
              new StudentsDTO() 
              { 
               Name= ss.Name, 
               Id= ss.StudentID 
              } 
             }.ToList() 
            }).ToList(); 
      return st; 

を取得しようとしていますですこれを行う方法を、教師テーブル内の各レコードの学生のコレクションを取得することはできませんよ?

+0

どのようなエラーが表示されますか? – Maxime

+0

1つの教師レコードの2つの一致するレコードが生徒テーブルにある場合、そのオブジェクトの生徒レコードの収集が得られません。 test.csには{id、text、Students count 2}が必要です。 – PRK

+0

あなたはあなたが望むことをするために "グループ化"が必要なようです。 –

答えて

2

1対多リレーションシップに適切なエンティティフレームワーククラス定義を使用した場合、クエリははるかに簡単になります。 Entity Frameworkはこれを行うため、結合を使用する必要はありません。

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

    // a Teacher has zero or more Students: 
    public virtual ICollection<Student> Students {get; set;} 
    ... 
} 

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

    // a Student has exactly one Teacher, via foreign key TeacherId 
    public int TeacherId {get; set;} 
    public virtual Teacher Teacher {get; set;} 
    ... 
} 

class MyDbContext : DbContext 
{ 
    public DbSet<Teacher> Teachers {get; set;} 
    public DbSet<Student> Students {get; set;} 
} 

適切Code First Conventionsが使用されているので、:1教師がゼロ以上の学生を持っており、すべての学生は、次のように正確に一つの教師、1対多のがモデル化されている場合は

Entity Framework Configure One-to-Many Relationship

を見ますこれは教師と生徒の間の一対一の関係をモデル化するために必要なすべてです。

異なるテーブル名や列名が必要な場合は、属性や流暢なAPIを使用する必要がありますが、Idは同じままです。教師には多くの生徒のICollectionがあり、生徒には外国人の鍵とそれに付随する教師の財産。

モデルが正しくクエリがはるかに簡単になります定義した:

var result = myDbContext.Teachers    // from the set of Teachers 
    .Where(teacher => teacher.TypeId == 2)  // take all teachers with TypeId 2 
    .Select(teacher => new Test()    // from every remaining Teacher, 
    {           // create one Test object 
     Id = teacher.Id,       // With Id is Teach Id 
     Text = teacher.Text,      // Text is teacher.Text 
     Students = teacher.Students    
      .Select(student => new StudentDTO() // from every Student of this Teacher 
      {         // create a StudentDTO object 
       Id = student.ID,     // with Id = student.Id 
       Name= student.Name,    // Name is student.Name 
      }) 
      .ToList(),       // create a list of these StudentDTOs 
    }) 
    .ToList();         // create a list of all Test objects 

私の経験は、私が正しく、すべての私のEntity Frameworkのクラスをモデル化するので、私はめったにもう参加を作成する必要がないということです。私は通常、結合されたテーブルの代わりにコレクションで考える。 Entity Frameworkは、内部的に結合を実行するタイミングを認識します。例えば

:あなたがしたい場合は、特定のTeacherCodeと教師のすべての生徒の名前:

IEnumerable<Student> GetStudentsOfTeacher(string teacherCode) 
{ 
    return myDbContext.Students 
     .Where(student => student.Teacher.TeacherCode == teacherCode); 
} 

Entity FrameworkのはあなたのためにTeacherIdの生徒と教師の参加を行います。

より簡単なlinqクエリとは別に、適切なモデリングによって、データベースのモデリング方法も隠されます。内部モデルが変更された場合、dbContextのユーザはコードを変更する必要はありません。

たとえば、教師と生徒の関係を多対多の関係に変更すると、教師には生徒が多く、生徒には多くの生徒がいる可能性があるため、生徒のクラスの定義は変更されず、したがって、クラスが変更されない限り、上記のクエリは変更する必要はありません。

5

左結合が必要な場合は、in ssjin ssj.DefaultIfEmpty()に置き換えます。

var st = (from tt in context.Teachers 
      where tt.TypeID == 2 
      join ss in context.Students 
      on tt.ID equals ss.teacherID into ssj 
      select new Test { 
       Id = tt.ID, 
       Text = tt.Text, 
       Students = (from ss in ssj 
          select new StudentsDTO() { 
           Name = ss.Name, 
           Id = ss.StudentID 
          }).ToList() 
      }).ToList(); 

return st; 

これはLINQに参加グループと呼ばれるものを使用する - クエリはSSJにおけるSSのコレクションと各TTと一致する(すなわち{TT、SSのグループ})。

関連する問題