实体框架包含左连接是否可能?

use*_*969 36 c# entity-framework left-join

我有以下表格

  1. ClassRoom(ClassID,ClassName)
  2. StudentClass(StudentID,ClassID)
  3. 学生(学生ID,学生姓名等)
  4. StudentDescription.(StudentDescriptionID,StudentID,StudentDescription)

我想检索有关student == 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
Run Code Online (Sandbox Code Playgroud)

现在我的问题.使用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;
    }
Run Code Online (Sandbox Code Playgroud)

再次尝试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();
Run Code Online (Sandbox Code Playgroud)

你可以看到我不知道我在这里做什么.如何将该Sql转换为EF查询?

RPM*_*984 34

对的,这是可能的.

首先,.Include使用您传递的导航属性进行LEFT OUTER JOIN .

这就是你如何在StudentStudentDescription之间明确地进行LEFT JOIN :

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

如您所见,它正在根据StudentsStudentDescriptions之间的实体关联执行JOIN .在EF模型中,您应该在Student实体上有一个名为StudentDescriptions的导航属性.上面的代码只是使用它来执行连接,并且默认为空.

代码基本相同.Include.

请不要对LEFT JOINLEFT 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();
        }
Run Code Online (Sandbox Code Playgroud)

基本上,确保所有FK都表示为模型上的导航属性,如果是,则不需要进行任何连接.您需要的任何关系都可以完成.Include.

  • 那么,真正的答案取决于它. - 这取决于所包含链接的可空性.如果可以为空,那么左连接,如果不可空,那么内连接. (13认同)
  • 这个答案是直接错误的,需要更新.@larsts是对的.如果导航属性的键可以为空并且实体映射使用WithOptional,则查询EF uses将使用LEFT JOIN.如果导航属性的键不可为空,或者实体映射使用WithRequired,则它使用INNER JOIN. (10认同)
  • 我不明白这个说法:“首先,.Include 执行左外连接”。据我所知 .Include 执行 INNER JOIN。 (2认同)

jBe*_*ger 26

我刚遇到这个问题,在我的情况下,EntityTypeConfiguration是错误的

我有:

   HasRequired(s => s.ClassRoom)
                .WithMany()
                .HasForeignKey(student => student.ClassRoomId);
Run Code Online (Sandbox Code Playgroud)

代替:

   HasOptional(s => s.ClassRoom)
                .WithMany()
                .HasForeignKey(student => student.ClassRoomId);
Run Code Online (Sandbox Code Playgroud)

似乎HasRequired在HasOptional进行LEFT JOIN时进行INNER JOIN.

  • 如果您使用 [Required] 属性标记 FK 属性,它还会执行 INNER JOIN(仅当该属性在数据库中为 NULL,且数据库模式和实体类之间不匹配时,这才有意义)。 (4认同)

Lap*_*mir 14

究竟:

  1. 如果StudentDescription.StudentId可以为空 - > EF执行LEFT JOIN,即 select * from Student s LEFT JOIN StudentDescription sd on s.StudentID=sd.StudentID.
  2. 否则EF会进行INNER JOIN.


Mr.*_*wny 9

的行为.Include

  • 该属性是必需的:始终翻译为INNER JOIN;
  • 外键的类型不可为空:INNER JOIN默认转换为 ,但您可以添加.IsRequired(false)with.HasForeignKey将其变为LEFT OUT JOIN
  • 属性的类型是 Collection 将始终转换为LEFT OUT JOIN.