Entity Framework включить с левым соединением это возможно? - PullRequest
32 голосов
/ 27 ноября 2010

У меня есть следующие таблицы

  1. ClassRoom (ClassID, ClassName)
  2. StudentClass (StudentID, ClassID)
  3. Student (StudentID, StudentName и т.д.).)
  4. StudentDescription.(StudentDescriptionID, StudentID, StudentDescription)

Я хочу получить всю информацию о студенте == 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 Query?

Ответы [ 3 ]

32 голосов
/ 29 ноября 2010

Да, это возможно.

Во-первых, .Include выполняет левое внешнее соединение, используя навигационное свойство , через которое вы проходите.

Вот как выЯвно выполнит LEFT JOIN между Student и StudentDescription :

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

Как вы можете видеть, он выполняет JOIN на основе ассоциации сущностей между Студенты и Студенческие описания .В вашей модели EF у вас должно быть навигационное свойство под названием StudentDescription в вашей сущности Student .Приведенный выше код просто использует это для выполнения объединения и по умолчанию, если он пуст.

Код в основном идентичен .Include.

Пожалуйста, не путайте с LEFTJOIN 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.

24 голосов
/ 11 февраля 2016

У меня просто была эта проблема, в моем случае это была неправильная конфигурация EntityType

У меня было:

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

Вместо:

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

ЭтоПохоже, что HasRequired выполняет ВНУТРЕННЕЕ СОЕДИНЕНИЕ, а HasOptional - ЛЕВОЕ СОЕДИНЕНИЕ.

13 голосов
/ 22 марта 2015

Точно:

  1. Если StudentDescription.StudentId имеет значение NULL -> EF выполняет LEFT JOIN, т.е. select * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID.
  2. В противном случае EF выполняет INNER JOIN.
...