J'ai les tableaux suivants
Je veux récupérer toutes les informations sur l'élève == 1
En sql, je ferais quelque chose comme CI-DESSOUS et j'obtiendrais toutes les informations sur un étudiant.
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
Maintenant, mon problème.En utilisant EF4, j'ai fait quelque chose comme ça, mais je ne peux pas le faire fonctionner. Vous pouvez également faire une inclusion et une jointure gauche
Tentative 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;
}
Tentative 2 à nouveau incomplète et erronée
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();
Comme vous pouvez le voir, je ne sais pas ce que je fais ici. Comment puis-je convertir ce SQL en une requête EF?
Oui c'est possible.
D'abord, .Include
effectue une jointure extérieure gauche, en utilisant la propriété de navigation que vous traversez.
C'est ainsi que vous feriez explicitement une jointure gauche entre Student et StudentDescription :
var query = from s in ctx.Students
from sd in s.StudentDescriptions.DefaultIfEmpty()
select new { StudentName = s.Name, StudentDescription = sd.Description };
Comme vous pouvez le voir, il effectue la JOIN en fonction de l'association d'entité entre Etudiants et StudentDescriptions . Dans votre modèle EF, vous devriez avoir une propriété de navigation appelée StudentDescriptions sur votre entité Student. Le code ci-dessus utilise simplement cela pour effectuer la jointure, et par défaut s'il est vide.
Le code est fondamentalement identique à .Include
.
Veuillez ne pas confondre avec LEFT JOIN vs LEFT OUTER JOIN.
C'est la même chose.
Le mot-clé "OUTER" est facultatif, je pense qu'il est là pour la compatibilité ANSI-92.
Juste .Include
tout ce dont vous avez besoin dans votre requête:
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();
}
Fondamentalement, assurez-vous que tous vos FK sont exprimés en tant que propriétés de navigation sur votre modèle, puis si c'est le cas, vous n'avez pas besoin de faire de jointures. Toutes les relations dont vous avez besoin peuvent être établies avec .Include
.
Je viens d'avoir ce problème, dans mon cas, c'était la EntityTypeConfiguration qui était incorrecte
J'ai eu:
HasRequired(s => s.ClassRoom)
.WithMany()
.HasForeignKey(student => student.ClassRoomId);
Au lieu de:
HasOptional(s => s.ClassRoom)
.WithMany()
.HasForeignKey(student => student.ClassRoomId);
Il semble que HasRequired fasse un INNER JOIN tandis que HasOptional fait un LEFT JOIN.
Exactement:
select * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID
.