Entity Framework включает в себя левое соединение, возможно ли это?
У меня есть следующие таблицы
- ClassRoom (ClassID, ClassName)
- StudentClass (StudentID, ClassID)
- Студент (StudentID, StudentName, Etc..)
- 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?
Ответы
Ответ 1
Да, это возможно.
Во-первых, .Include
выполняет LEFT OUTER JOIN, используя навигационное свойство, которое вы проходите.
Вот как вы бы явно делали 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 на основе ассоциации сущностей между Student и StudentDescriptions. В вашей модели EF у вас должно быть навигационное свойство 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
.
Ответ 2
У меня была эта проблема, в моем случае это была ошибка 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.
Ответ 3
именно:
- Если StudentDescription.StudentId имеет значение NULL → EF выполняет LEFT JOIN, т.е.
select * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID
.
- В противном случае EF делает INNER JOIN.