C#操作SQLite计算GPA时仅读取单门课程成绩的问题排查
问题背景
搭建高校教务系统时,在GpaCal()方法中通过SQLite数据库计算学生指定学期GPA,学生表结构如下:
原实现逻辑为:先查询指定学期的课程总数,初始化对应长度的成绩、学分、加权绩点数组,通过SQLiteDataReader读取查询结果后,在循环内完成分数到绩点的换算,最终累加总加权绩点除以总学分得到GPA。实际运行时无法遍历所有课程记录,仅能读取到单门课程的成绩数据。
问题根因
故障由3个核心逻辑错误导致:
- 返回语句位置错误:
return ClassGpa;被写在while(reader.Read())循环体内部,reader.Read()读到第一条课程记录、跑完内部逻辑后就直接触发返回,循环直接终止,后续所有课程记录不会被读取。 - 循环嵌套逻辑错误:
while(reader.Read())本身的作用是逐行遍历查询返回的每一条课程记录,原代码在该循环内部又嵌套了一层遍历全数组长度的for循环,每读一条记录就从数组下标0开始反复覆盖数组内容,即使调整return位置,最终数组存储的也会是最后一条记录重复N次的错误数据。 - 边界判断与资源管理隐患:直接拼接SQL语句存在注入风险,数据库连接、Command、DataReader未做资源释放,字段空值未做判断,绩点区间用固定上限(如89.99)判断存在浮点数精度遗漏问题。
修复实现
GPA计算不需要提前查询课程总数、也不需要数组存储所有课程明细,只需要在遍历记录时累计「加权绩点总和」和「总学分」两个核心值即可,修复后代码如下:
public double GpaCal() { double totalWeightedGpa = 0; double totalCredit = 0; connect(); try { // 用参数化查询替代SQL拼接,避免注入风险 string querySql = $"select grade, ECTS from {student} where term = @termInfo;"; using (SQLiteCommand command = new SQLiteCommand(querySql, myConnection)) { command.Parameters.AddWithValue("@termInfo", termInfo); using (SQLiteDataReader reader = command.ExecuteReader()) { // 逐行遍历所有课程记录 while (reader.Read()) { int gradeOrdinal = reader.GetOrdinal("grade"); int ectsOrdinal = reader.GetOrdinal("ECTS"); // 空值跳过,避免转换异常 if (reader.IsDBNull(gradeOrdinal) || reader.IsDBNull(ectsOrdinal)) continue; double mark = reader.GetDouble(gradeOrdinal); int credit = Convert.ToInt32(reader.GetDouble(ectsOrdinal)); // 左闭右开区间判断绩点,避免浮点数精度问题 double coursePoint = mark switch { >= 90 and <= 100 => 4.0, >= 85 and < 90 => 3.5, >= 80 and < 85 => 3.0, >= 75 and < 80 => 2.5, >= 70 and < 75 => 2.0, >= 65 and < 70 => 1.5, >= 60 and < 65 => 1.0, >= 50 and < 60 => 0.5, > 0 and < 50 => 0.0, _ => 0.0 }; totalWeightedGpa += coursePoint * credit; totalCredit += credit; } } } } finally { // 确保连接关闭释放 if (myConnection.State == System.Data.ConnectionState.Open) myConnection.Close(); } if (totalCredit == 0) return 0.0; ClassGpa = totalWeightedGpa / totalCredit; return ClassGpa; }
关键修改说明
- 移除了多余的课程总数预查询、数组初始化逻辑,遍历数据时直接累计计算所需的核心值,减少不必要的内存开销。
- 将return语句移出数据读取循环,确保所有课程记录遍历完成后再执行最终GPA计算和结果返回。
- 删除了错误的嵌套for循环,逐行读取时直接处理当前行的成绩、学分数据,不存在数组值被反复覆盖的问题。
- 新增参数化查询、空值判断、资源释放逻辑,规避SQL注入、转换异常、内存泄漏等隐患。
- 调整绩点区间判断为左闭右开写法,解决原代码浮点数边界判断遗漏的问题。
内容的提问来源于stack exchange,提问作者mohammad_soqar101
相关产品推荐
相关产品推荐

