2010-11-27 14 views
22

J'ai les tableaux ci-dessousEntity Framework include avec la jointure gauche est-ce possible?

  1. Classroom (CLASSID ClassName)
  2. StudentClass (StudentID, ClassID)
  3. étudiants (StudentID, StudentName, Etc ..)
  4. StudentDescription. (StudentDescriptionID, StudentID, StudentDescription)

Je veux récupérer toutes les informations sur les étudiants == 1

Dans sql je ferais quelque chose comme ci-dessous et obtenir toutes les informations sur un étudiant. Maintenant, mon problème.En utilisant EF4 j'ai fait quelque chose comme ça, mais je ne peux pas le faire fonctionner. pouvez-vous faire également un include 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 fois 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?

Répondre

27

Oui, c'est possible.

Tout d'abord, .Include fait une jointure gauche, en utilisant la propriété de navigation que vous traversez.

Voici comment vous feriez explicitement LEFT JOIN entre étudiants 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 est d'effectuer le REJOIGNEZ basé sur l'association d'entité entre étudiants et StudentDescriptions. Dans votre modèle EF, vous devriez avoir une propriété de navigation appelé StudentDescriptions sur votre entité étudiant. 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 OUTPUT JOIN.

Ce sont la même chose.

Le mot-clé « extérieur » est facultative, je crois qu'il est là pour ANSI-92 compatibilité.

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 de sont exprimés en propriétés de navigation sur votre modèle, puis le cas échéant, vous n'avez pas besoin de faire toutes les jointures. Toutes les relations dont vous avez besoin peuvent être effectuées avec .Include.

+1

merci pour votre temps et réponse. L'exemple d'inclusion fonctionne! cependant le premier produit une jointure croisée. Je pourrais être totalement faux mais quand vous faites 2 froms doesnt produit une jointure croisée? – user9969

+0

Je n'ai pas compris cette déclaration: "Tout d'abord, .Include fait une jointure gauche,". Pour autant que je peux dire .Include effectue une INNER JOIN. – Dror

+0

Non, '' .Include'' fait un OUTER JOIN. Si vous incluez une propriété qui se trouve être vide (pas là), l'original est toujours retourné. –

7

Exactement:

  1. Si StudentDescription.StudentId est annulable -> EF effectue LEFT JOIN, à savoir select * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID.
  2. Sinon, EF fait INNER JOIN.
15

Je viens d'avoir ce problème, dans mon cas, il était le EntityTypeConfiguration qui avait tort

j'avais:

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

Au lieu de:

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

Il semble HasRequired marques un INNER JOIN alors que HasOptional fait un LEFT JOIN.