web-dev-qa-db-ja.com

左結合でEntity Frameworkを含めることは可能ですか?

私は次の表を持っています

  1. ClassRoom(ClassID、ClassName)
  2. StudentClass(StudentID、ClassID)
  3. 学生(StudentID、StudentName、Etc ..)
  4. StudentDescription。 (StudentDescriptionID、StudentID、StudentDescription)

Student == 1のすべての情報を取得したい

SQLでは、以下のようなことをして、学生に関するすべての情報を取得します。

 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クエリに変換するにはどうすればよいですか?

34
user9969

はい、可能です。

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

これは、StudentStudentDescriptionの間で明示的にLEFT JOINを行う方法です。

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

ご覧のとおり、StudentsStudentDescriptionsの間のエンティティの関連付けに基づいてJOINを実行しています。 EFモデルでは、StudentエンティティにStudentDescriptionsというナビゲーションプロパティが必要です。上記のコードは単純にそれを使用して結合を実行し、空の場合はデフォルトにしています。

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

LEFT JOIN vs LEFT 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で実行できます。

33
RPM1984

私はちょうどこの問題を抱えていました、私の場合は間違っていたEntityTypeConfigurationでした

私が持っていた:

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

の代わりに:

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

HasRequiredはINNER JOINを作成し、HasOptionalはLEFT JOINを作成しているようです。

25
jBelanger

丁度:

  1. StudentDescription.StudentIdがnull可能-> EFがLEFT JOINを実行する場合、つまりselect * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID
  2. それ以外の場合、EFは内部結合を行います。
14