2010-11-27 13 views
22

は、私は、次の表エンティティフレームワークに左結合を含めることは可能ですか?

  1. 教室(のClassID、クラス名)
  2. StudentClass(StudentID、のClassID)
  3. 学生(StudentID、StudentName、等。)
  4. StudentDescriptionを持っています。 (StudentDescriptionID、StudentID、StudentDescription)

は私がBELOWような何かをし、学生に関するすべての情報を得るでしょうSQLで学生== 1

上のすべての情報を取得します。

select * from Student s 
join StudentClass sc on s.StudentID=sc.StudentID 
join ClassRoom c on sc.ClassID=c.ClassID 
left join StudentDescription sd on s.StudentID=sd.StudentID 
where s.StudentID=14 

私の問題。EF4を使用して、私はこのようなことをしましたが、動作させることはできません。あなたは私がここでやっているものを知らない見ることができるように はまた、あなたには、左は

試み1

private static StudentDto LoadStudent(int studentId) 
    { 
     StudentDto studentDto = null; 
     using (var ctx = new TrainingContext()) 
     { 
      var query = ctx.Students 
       .Include("ClassRooms") 
       .Include("StudentDescriptions") 
       .Where(x=>x.StudentID==studentId) 
       .SingleOrDefault(); 

      studentDto = new StudentDto(); 
      studentDto.StudentId = query.StudentID; 
      studentDto.StudentName = query.StudentName; 
      studentDto.StudentDescription = ?? 

     } 

     return studentDto; 
    } 

試み2再び不完全で、間違った

using (var ctx = new TrainingContext()) 
     { 
      var query = (from s in ctx.Students 
          .Include("ClassRooms") 
         join sd in ctx.StudentDescriptions on s.StudentID equals sd.StudentID into g 
         from stuDesc in g.DefaultIfEmpty() 
         select new 
            { 
             Name=s.StudentName, 
             StudentId=s.StudentID, 

     }).SingleOrDefault(); 

に参加しないことができます。 SqlをEFクエリに変換するにはどうすればよいですか?

答えて

27

はい、可能です。

まず、.Includeは、ナビゲーションプロパティを使用して、LEFT OUTER JOINを実行します。

これは、あなたが明示的にLEFTを行うだろう方法ですが学生StudentDescription間のJOIN:

var query = from s in ctx.Students 
      from sd in s.StudentDescriptions.DefaultIfEmpty() 
      select new { StudentName = s.Name, StudentDescription = sd.Description }; 

あなたが見ることができるように、それは、JOIN 学生間のエンティティの関連付けに基づいてを行っていますStudentDescriptions EFモデルでは、StudentDescriptionsというあなたの生徒のエンティティというナビゲーションプロパティが必要です。上記のコードは単にそれを使用して結合を実行し、空の場合はデフォルトにします。

コードは基本的に.Includeと同じです。

と混同しないでください。LEFT JOINLEFT OUTER JOIN。

これらは同じものです。

"OUTER"キーワードはオプションですが、ANSI-92との互換性があると思います。

あなたのクエリに必要なだけの.Includeすべて:

using (var ctx = new TrainingContext()) 
     { 
      studentDo = ctx.Students 
       .Include("ClassRooms") 
       .Include("StudentDescriptions") 
       .Where(x=>x.StudentID==studentId) 
       .Select(x => new StudentDto 
         { 
          StudentId = x.StudentId, 
          StudentName = x.StudentName 
          StudentDescription = x.StudentDescription.Description 
         }) 
       .SingleOrDefault(); 
     } 

は基本的に、すべてのあなたのFKさんがモデルのナビゲーションプロパティとして表現されていることを確認し、その後もしそうなら、あなたはいずれかの加入する必要はありません。必要な関係は .Includeで行うことができます。

+1

あなたの時間と返信に感謝します。しかし、最初のものはクロスジョイントを生成します。私は全く間違っているかもしれませんが、2つの場合はクロスジョイントを生成しませんか? – user9969

+0

私はこの声明を理解していませんでした: "まず、LEFT OUTER JOINを含めます。"私が言うことができる限り、インクルードはINNER JOINを実行します。 – Dror

+0

いいえ、 '' .Include''はOUTER JOINを行います。空の(存在しない)プロパティを含めると、元のものが返されます。 –

7

正確:

  1. StudentDescription.StudentIdがNULL可能である場合 - > EFが左を実行する、すなわちselect * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID、JOIN。
  2. それ以外の場合、EFはINNER JOINを実行します。
15

は、私はこの問題を抱えていた、私の場合には、それは私が持っていた

間違っていたEntityTypeConfigurationた:

HasRequired(s => s.ClassRoom) 
       .WithMany() 
       .HasForeignKey(student => student.ClassRoomId); 

の代わりに:

HasOptional(s => s.ClassRoom) 
       .WithMany() 
       .HasForeignKey(student => student.ClassRoomId); 

をそれはHasRequiredになりそうですHasOptionalがLEFT JOINを実行している間はINNER JOINを返します。

関連する問題