Linq查询使用select new语句返回所有记录

时间:2017-07-17 23:10:01

标签: c# .net entity-framework linq lambda

我有桌老师和桌上学生,对于表格中的每个记录'老师'表格中将有多个记录“学生”。这是我的模型类

public class Test
{
    public int Id { get; set; }
    public string Text { get; set; }
    public List<StudentsDTO> Students{ get; set; } 
}

这是我的linq查询我试图获取记录

     var st = (from tt in context.Teachers
                                    join ss in context.Students
                                    on tt.ID equals ss.teacherID
                                    where tt.TypeID == 2
                                    select new Test
                                    {
                                        Id = tt.ID,
                                        Text = tt.Text,
                                        Students= new List<StudentsDTO>()
                                        {
                                            new StudentsDTO()
                                            {
                                                Name= ss.Name,
                                                Id= ss.StudentID
                                            }
                                        }.ToList()
                                    }).ToList();
            return st;

我无法为教师表中的每条记录收集学生,怎么做?

2 个答案:

答案 0 :(得分:5)

如果您需要左连接,请将in ssj替换为in ssj.DefaultIfEmpty()

var st = (from tt in context.Teachers
          where tt.TypeID == 2
          join ss in context.Students
          on tt.ID equals ss.teacherID into ssj
          select new Test {
              Id = tt.ID,
              Text = tt.Text,
              Students = (from ss in ssj
                          select new StudentsDTO() {
                              Name = ss.Name,
                              Id = ss.StudentID
                           }).ToList()
          }).ToList();

return st;

这在LINQ中使用所谓的组连接 - 查询将每个tt与ssj中的ss集合(即{tt,group of ss})进行匹配。

答案 1 :(得分:5)

如果您对一对多关系使用了正确的实体框架类定义,那么您的查询将更加简单。你甚至不必使用连接,因为实体框架会为你做这件事。

请参阅Entity Framework Configure One-to-Many Relationship

如果一位教师拥有零个或多个学生,并且每个学生只有一位教师,那么一对多的建模如下:

class Teacher
{
    public int Id {get; set;}

    // a Teacher has zero or more Students:
    public virtual ICollection<Student> Students {get; set;}
    ...
}

class Student
{
    public int Id {get; set;}

    // a Student has exactly one Teacher, via foreign key TeacherId
    public int TeacherId {get; set;}
    public virtual Teacher Teacher {get; set;}
    ...
}

class MyDbContext : DbContext
{
    public DbSet<Teacher> Teachers {get; set;}
    public DbSet<Student> Students {get; set;}
}

因为使用了正确的Code First Conventions,所以只需要模拟教师和学生之间的一对多关系。

  

在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多,......)

如果您需要不同的表名或列名,则必须使用属性或流畅的API,但ID仍然相同:教师对其拥有的许多学生进行ICollection,并且学生有一个外国钥匙和一个教师的财产。

正确定义模型后,您的查询更简单,更直观:

var result = myDbContext.Teachers                // from the set of Teachers
    .Where(teacher => teacher.TypeId == 2)       // take all teachers with TypeId 2
    .Select(teacher => new Test                  // from every remaining Teacher,
    {                                            // create one Test object
        Id = teacher.Id,                         // With Id is Teach Id
        Text = teacher.Text,                     // Text is teacher.Text
        Students = teacher.Students              
            .Select(student => new StudentDTO    // from every Student of this Teacher
            {                                    // create a StudentDTO object
                Id = student.ID,                 // with Id = student.Id
                Name= student.Name,              // Name is student.Name
            })
            .ToList(),                           // create a list of these StudentDTOs
     })
     .ToList();                                  // create a list of all Test objects

我的经验是,由于我正确地为所有实体框架类建模,因此我很少再创建连接。我通常认为在集合中而不是连接表。实体框架将知道必须执行哪个(组)连接。

例如:如果您希望教师的所有学生的姓名都具有某个TeacherCode:

IEnumerable<Student> GetStudentsOfTeacher(string teacherCode)
{
    return myDbContext.Students
       .Where(student => student.Teacher.TeacherCode == teacherCode);
}

实体框架将为您加入TeacherId上的学生和教师。

  

如果你想进行小组加入(一个包含所有子项目的项目,一个包含所有学生的教师),请从单侧开始。如果你想做一个平坦的加入(一个有这个老师的学生)从多方开始。

除了更简单的linq查询之外,正确的建模还隐藏了数据库建模的方式。如果内部模型发生变化,dbContext的用户将不必更改其代码。

例如,如果您将师生关系更改为多对多关系,这意味着教师可能有很多学生,而学生可能有很多教师,那么您的教师课程的定义不会改变,因此只要课程没有改变,上面的查询就不会改变。