私は次の表を持っています
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クエリに変換するにはどうすればよいですか?
はい、可能です。
まず、.Include
は、通過するナビゲーションプロパティを使用して、LEFT OUTER JOINを実行します。
これは、StudentとStudentDescriptionの間で明示的にLEFT JOINを行う方法です。
var query = from s in ctx.Students
from sd in s.StudentDescriptions.DefaultIfEmpty()
select new { StudentName = s.Name, StudentDescription = sd.Description };
ご覧のとおり、StudentsとStudentDescriptionsの間のエンティティの関連付けに基づいて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
で実行できます。
私はちょうどこの問題を抱えていました、私の場合は間違っていた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を作成しているようです。
丁度:
select * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID
。