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

时间:2010-11-27 08:47:42

标签: c# entity-framework left-join

我有以下表格

  1. ClassRoom(ClassID,ClassName)
  2. StudentClass(StudentID,ClassID)
  3. 学生(StudentID,StudentName,Etc ..)
  4. StudentDescription。 (StudentDescriptionID,StudentID,StudentDescription)
  5. 我想检索有关student == 1

    的所有信息

    在sql中,我会做类似于BELOW的事情并获取有关学生的所有信息。

     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查询?

5 个答案:

答案 0 :(得分:32)

是的,这是可能的。

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

这是您在学生 StudentDescription 之间明确执行LEFT JOIN的方式:

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

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

代码与.Include基本相同。

请不要与 LEFT JOIN 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完成。

答案 1 :(得分:21)

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

我有:

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

而不是:

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

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

答案 2 :(得分:13)

完全:

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

答案 3 :(得分:1)

如果你想要一个 1 对 1 的关系,你可以简单地映射你的外来 Id 并使它可以为空。

public int? MyForeignClassId { get; set; }
public MyForeignClass MyForeignClass { get; set; }

答案 4 :(得分:0)

.Include 的行为:

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