我正在开发一个 C# 应用程序,该应用程序与 MySQL 数据库交互,以检索有关教师及其教授的课程的信息。我有一个教师表,其中包含有关教师的信息,还有一个班级表,其中包含有关课程的详细信息,包括与每门课程关联的教师 ID。每个老师可以教授多门课程。
这是我当前的代码:
[HttpGet]
[Route("api/teacherdata/findteacher/{teacherid}")]
public Teacher FindTeacher(int TeacherId)
{
Teacher NewTeacher = new Teacher();
MySqlConnection Conn = School.AccessDatabase();
Conn.Open();
MySqlCommand cmd = Conn.CreateCommand();
cmd.CommandText = "SELECT * FROM teachers LEFT JOIN classes ON teachers.teacherid = classes.teacherid WHERE teachers.teacherid = @TeacherId;";
cmd.Parameters.AddWithValue("@TeacherId", TeacherId);
cmd.Prepare();
MySqlDataReader ResultSet = cmd.ExecuteReader();
while (ResultSet.Read())
{
// Fetch teacher information
NewTeacher.TeacherId = Convert.ToInt32(ResultSet["teacherid"]);
NewTeacher.TeacherFname = ResultSet["teacherfname"].ToString();
// ... (other teacher details)
// Fetch course information
NewTeacher.ClassName = ResultSet["classname"].ToString();
// ... (other course details)
}
Conn.Close();
return NewTeacher;
}
我想修改此方法以包含老师教授的所有课程的列表。我怎样才能实现这个目标?
任何帮助将不胜感激。谢谢!
您现有的查询将包含这些信息,但重要的是要了解 SQL 中的 JOIN 将在表之间产生称为笛卡尔积的结果。例如,如果您有 1 位老师负责 2 门课程并加入表格,您将得到 2 个结果行:
TeacherId TeacherFName ClassId CourseName
1 John 1 Chemistry
1 John 2 Physics
...作为一个简单的示例,因此读取数据的代码需要考虑到这一点,而不是为两行创建两个教师。因此,如果您希望找到通过 ID 加载的单个老师,我会建议如下所示:
public Teacher FindTeacher(int TeacherId)
{
Teacher? NewTeacher = null;
// Note: Any class that is Disposable should be disposed. use using.
using MySqlConnection Conn = School.AccessDatabase();
Conn.Open();
MySqlCommand cmd = Conn.CreateCommand();
cmd.CommandText = "SELECT * FROM teachers LEFT JOIN classes ON teachers.teacherid = classes.teacherid WHERE teachers.teacherid = @TeacherId;";
cmd.Parameters.AddWithValue("@TeacherId", TeacherId);
cmd.Prepare();
MySqlDataReader ResultSet = cmd.ExecuteReader();
while (ResultSet.Read())
{
if (NewTeacher == null) // Populate the teacher on the first row read.
NewTeacher = new Teacher
{
TeacherId = Convert.ToInt32(ResultSet["teacherid"]);
TeacherFname = ResultSet["teacherfname"].ToString();
// ...
};
// Fetch course information and add to the teacher.
NewTeacher.Courses.Add(new Course
{
ClassName = ResultSet["classname"].ToString();
// ... (other course details)
}
}
Conn.Close();
return NewTeacher;
}
这里您的老师最初为空,因此当我们读取第一行时,我们会将与老师相关的详细信息加载到一个新实例中。教师类将包含课程对象的集合来保存课程相关的详细信息。这应该在 Teacher 类中自动初始化为新的
List<Course>
:
public ICollection<Course> Courses { get; private set; } = new List<Course>();
现在,当您迭代记录时,您可以为每一行填充课程。
当您连接更多表时,笛卡尔积可能会给查询带来一些重大成本,因为不仅每行中的列数会增加以考虑所有表字段,而且返回的总行数是所有相关行的乘积。一条教师记录可能会导致数十、数百或更多行需要筛选,具体取决于表的连接方式。在许多情况下,拆分查询效率更高。
我建议学习像实体框架这样的 ORM 来处理所有 SQL 和笛卡尔积处理,以读取和更新数据。它可以将这样的方法简化为:
public Teacher FindTeacher(int teacherId)
{
using var accessDbContext = new AccessDbContext();
var teacher = accessDbContext.Teachers
.Include(t => t.Courses)
.AsNoTracking()
.Single(t => t.TeacherId == teacherId);
return teacher;
}
或者,如果您不需要教师和课程的每一列,您可以使用
Select
轻松将其投影到 DTO 或 ViewModel 类,以获取调用者实际需要的列。 (建议不要传递实体类)