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

PRK*_*PRK 1 .net c# linq lambda entity-framework

我有表老师和表学生,对于表'老师'中的每个记录,表'学生'中将有多个记录.这是我的模特课

public class Test
{
    public int Id { get; set; }
    public string Text { get; set; }
    public List<StudentsDTO> Students{ get; set; } 
}
Run Code Online (Sandbox Code Playgroud)

这是我的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;
Run Code Online (Sandbox Code Playgroud)

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

Net*_*age 5

如果你需要一个左连接,更换in ssjin 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;
Run Code Online (Sandbox Code Playgroud)

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


Har*_*lse 5

如果您对一对多关系使用了正确的实体框架类定义,那么您的查询将更加简单.您甚至不必使用连接,因为实体框架会为您执行此操作.

请参阅实体框架配置一对多关系

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

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;}
}
Run Code Online (Sandbox Code Playgroud)

因为使用了正确的代码优先约定,所以只需要模拟教师和学生之间的一对多关系.

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

如果您需要不同的表名或列名,则必须使用属性或流畅的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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

例如,如果您将教师 - 学生关系更改为多对多关系,意味着教师可能有许多学生,而学生可能有许多教师,则不会更改教师课程的定义,因此上面的查询获胜只要课程不会改变,就必须改变.