Linq 查询,使用选择"新建语句"返回所有记录



我有表老师和表学生,对于表"老师"中的每条记录,表"学生"中将有多个记录。这是我的模型类

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;

我无法在教师表中获取每条记录的学生集合,该怎么办?

如果对一对多关系使用正确的实体框架类定义,则查询将简单得多。您甚至不必使用联接,因为实体框架会为您执行此操作。

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

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

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;}
}

由于使用了正确的代码优先约定,因此只需对教师和学生之间的一对多关系进行建模

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

如果你想要不同的表名或列名,你必须使用属性或流畅的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

我的经验是,由于我对所有实体框架类都进行了正确的建模,因此我很少再需要创建联接了。我通常考虑集合而不是连接表。实体框架将知道必须执行哪个(组(联接。

例如:如果您想要具有特定教师代码的教师所有学生的姓名:

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

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

如果要执行小组加入(一个项目及其所有子项目,一个教师及其所有学生(,请从一侧开始。如果你想做一个平面连接(一个学生与这个老师(,从多边开始。

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

例如,如果将"教师-学生关系"更改为"多对多"关系,这意味着教师可能有许多学生,而学生可能有许多教师,则教师类的定义不会更改,因此只要类不会更改,上述查询就不必更改。

如果需要左联接,请将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 }(匹配。

最新更新