首页 > 解决方案 > 用于从 3 个表中获取数据的 LINQ 查询

问题描述

我正在使用 SQL Server 2017、.Net 4.5 和 EF 核心。

我有以下表格: Student_Course:有 Student_Id、Course_ID 和 Student _Course_ID - pk。

学生:First_Name、Last_Name、Email、Student_ID - PK 课程:Id pk、姓名

我正在尝试检索具有各自课程的学生列表。我还需要每个学生的课程数量。

对于上面提到的表格,我在 C# Student_Course 中有以下实体:具有学生和课程列表的导航属性学生:课程:

我正在尝试使用 LINQ 进行此查询:

控制器:

public IList<StudentCourse> GetStudents()
{
Student_CourseContext scContext = new Student_CourseContext();
             
var studentCourses = (from sc in scContext.Student_Course
                      from student in sc.Students.Where( x => x.Student_ID == 
     sc.Student_ID) 
                      from course in sc.Courses.Where (x => x.ID == sc.Course_ID)
                      where sc.Student_ID == student.Student_ID
                      && sc.Course_ID == course.ID
                      && student.First_Name != "None"
                      //join course in sc.Courses
                     //from sc in studentCourseEntity.Student_Courses.GroupBy( x => x.Student_ID)
                     select new StudentCourse
                     {
                             StudentName = student.First_Name + ' ' + student.Last_Name,
                            //CourseCount = sc.Gr,
                            Course = string.Join(",", course.Name)
                     }).ToList();
    return studentCourses.ToList();
}



        }

它返回一个这样的查询:

SELECT ([s0].[First_Name] + CAST(N' ' AS nvarchar(max))) + [s0].[Last_Name], [c].[Name]
FROM [Student_Course] AS [s]
INNER JOIN [Student] AS [s0] ON ([s].[Student_Course_ID] = [s0].[Student_Course_ID]) AND ([s].[Student_ID] = [s0].[Student_ID])
INNER JOIN [Course] AS [c] ON ([s].[Student_Course_ID] = [c].[Student_Course_ID]) AND ([s].[Course_ID] = [c].[ID])
WHERE (([s].[Student_ID] = [s0].[Student_ID]) AND ([s].[Course_ID] = [c].[ID])) AND (([s0].[First_Name] <> N'None') OR [s0].[First_Name] IS NULL)

它不是加入指定的列,而是加入 STudent_Course_ID,这是 Student_Course 表的主键。由于这个加入,我得到了错误:

列名“Student_Course_ID”无效。列名“Student_Course_ID”无效。

因为学生和课程表没有这个字段。请让我知道如何使这项工作。

我尝试了 mode.OnCreating 方法来定义这些表之间的关系,但我能够在 Student、Student_Course 和 Course 表之间进行映射。

提前致谢。

标签: c#sql-serverlinq

解决方案


因此,您希望为每个学生提供他的姓名以及他参加的所有课程名称的列表(集合?)。

var studentsWithTheCoursesTheyAttend = dbContext.Students
    .Select(student => new
    {
        Name = student.First_Name + ' ' + student.Last_Name,
        Courses = dbContext.Student_Course
            .Where(studentCourse => studentCourse.StudentId == student.Id)
            .Select(studentCourse => dbContext.Courses
                .Where(course => course.Id == studentCourse.CourseId)
                .Select(course => course.Name)
                .FirstOrDefault())
            .ToList(),                    
    }

解释:从完整的学生表中的每个学生中,取他的名字:

... = dbContext.Students
    .Select(student => new
    {
        Name = student.First_Name + ' ' + student.Last_Name,

同时选择该学生的所有 Student_Courses(= 所有 Student_Courses 的外键 StudentId 等于 Student 的主键):

Courses = dbContext.Student_Course
    .Where(studentCourse => studentCourse.StudentId == student.Id)

您希望从该学生的每个选定 Student_Course 中获取该 Student_Course 所指的课程名称。为此,我们将首先获取主键等于外键 StudentCourse.CourseId 的所有课程:

        .Select(studentCourse => dbContext.Courses
            .Where(course => course.Id == studentCourse.CourseId)

好吧,我们不想要完整的课程,我们只想要它的名称:

            .Select(course => course.Name)

好吧,我们知道每个 studentCourse 只会有它所引用的一门课程,而不是零,不超过一门。毕竟,外键studentCourse.CourseId指的是一门课程。

因此,我们只需要采取第一个。我本来可以使用First(),但是 IQueryable 中的一些 Providers 在使用 First 时会报告问题,因此我使用FirstOrDefault().

             .FirstOrDefault(),

所以到现在为止,我有他的名字,以及他参加的所有课程的名字。将此作为课程列表:

Courses = ...
    .ToList(),

所以现在你有这样的东西:

{
    Name = "Sukumar Krishnamurthy",
    Courses =
        {
            "Advanced .NET",
            "All aspects of LINQ",
            "Ups and downs of C#",
        },
},
{
    Name = "Harald Coppoolse",
    Courses =
        {
            "Windows Services",
            "REST in a proper manner",
        },
},

属性Courses是学生参加的课程名称列表。列表的长度代表参加过的课程的数量。

如果需要,您可以将此课程列表转换为一个带有名称的字符串。但是我不确定这会提高可读性:

"Windows Services REST in a proper manner"

推荐阅读