web-dev-qa-db-fra.com

Entity Framework inclure avec jointure gauche est-ce possible?

J'ai les tableaux suivants

  1. ClassRoom (ClassID, ClassName)
  2. StudentClass (StudentID, ClassID)
  3. Étudiant (StudentID, StudentName, Etc ..)
  4. StudentDescription. (StudentDescriptionID, StudentID, StudentDescription)

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?

34
user9969

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.

33
RPM1984

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.

25
jBelanger

Exactement:

  1. Si StudentDescription.StudentId est nullable -> EF effectue un LEFT JOIN, c'est-à-dire select * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID.
  2. Sinon, EF fait INNER JOIN.
14
Lapenkov Vladimir