简介:这是一套面向计算机相关专业学生与Java Web开发初学者的在线英语自学系统完整项目资料,采用C#、ASP.NET与SQL Server技术栈,基于BS架构实现,适合作为课程设计、毕业设计或自学练手参考。资源以zip压缩包形式提供,内含项目全套源码与完整文档,源码经过测试校正,可保证百分百成功运行,方便读者直接部署与二次开发。压缩包整体约636KB,文件以源码文件与说明文档为主,源码部分对应系统各功能模块的实现逻辑,文档部分则覆盖设计思路与使用说明,便于对照理解整体结构。目前已有318人学习下载,说明该资源在同类项目设计中具备一定参考价值。读者可从中获取完整的系统实现方案、数据库设计思路与前后端交互逻辑,快速掌握ASP.NET在BS架构项目中的实际应用方式,并借助文档梳理开发流程,为后续项目开发或答辩准备提供直接帮助。
1. 在线英语自学系统:从一份课程设计到能跑通的 B/S 全栈项目
很多同学做课程设计时,第一反应是去搜「在线英语自学系统源码」,下载下来发现跑不起来——数据库连不上、IIS 配置报错、页面样式全乱。这个标题背后其实是一个典型的 C# + ASP.NET + SQL Server 的 B/S 架构项目,核心解决的是「学生在线刷题、看课程、做自测,管理员后台管内容」这类需求。它适合两类人:一是需要交课程设计或毕设的在校生,二是想用 .NET 技术栈练手全栈开发的新手。我见过太多人卡在环境配置这一步就放弃了,其实只要把数据库脚本、连接字符串、IIS 站点这三件事理顺,整个系统半小时内就能在本地跑起来。下面我按实际落地的顺序,把这个项目从架构选型到部署排错完整拆一遍。
2. 技术选型与架构拆解:为什么是 C# + ASP.NET + SQL Server
2.1 B/S 架构在这个场景下的真实优势
B/S 架构的核心特点是客户端只需要浏览器,所有业务逻辑和数据处理都在服务端完成。对于在线英语自学系统来说,这个选择不是跟风,而是有实际理由的。学生端要做的无非是登录、浏览课程、做练习题、查看成绩,这些操作对客户端计算能力几乎没有要求,用浏览器承载完全够用。而管理员端需要上传课程资料、管理题库、查看学习统计,这些功能放在服务端统一处理,避免了客户端版本不一致的问题。
对比 C/S 架构,B/S 的部署成本低很多。C/S 需要每台学生机安装客户端,更新时逐台升级,维护量随用户数线性增长。B/S 只需要维护一台服务器,学生打开浏览器输入地址就能用。当然 B/S 也有代价——页面响应依赖网络、复杂交互不如原生客户端流畅,但对于英语自学这种以内容展示和答题为主的场景,这些代价可以接受。
从技术栈角度看,ASP.NET 在这个项目里承担的是服务端渲染和后台逻辑处理的角色。早期 ASP.NET WebForms 用控件拖拽的方式开发,上手快但前后端耦合严重;后来 ASP.NET MVC 把模型、视图、控制器分离,更适合多人协作和后期维护。这个项目标题没有指定具体是 WebForms 还是 MVC,但从「设计与实现」的定位来看,常见做法是用 ASP.NET MVC 或者 ASP.NET Core MVC,因为分层清晰,代码可读性好,答辩时也更容易讲清楚架构。
2.2 数据库表结构设计的几个关键决策
SQL Server 作为数据存储层,在这个系统里要承载用户信息、课程内容、题库、答题记录、成绩统计这几类数据。表结构设计直接决定了后期功能扩展的难易程度。我一般会先把核心实体列出来,再考虑它们之间的关系。
用户表是基础,至少要有用户 ID、用户名、密码哈希、角色(学生/管理员)、注册时间、最后登录时间。密码绝对不能明文存储,哪怕是个课程设计项目,用 SHA256 加盐哈希也是基本要求。角色字段决定了登录后跳转到学生端还是管理端。
课程表要包含课程 ID、课程名称、课程描述、封面图片路径、难度等级、创建时间、是否发布。难度等级可以用枚举值(初级/中级/高级),方便学生按水平筛选。是否发布这个字段很关键——管理员编辑课程时先存为草稿,确认无误后再发布,避免半成品内容被学生看到。
题库表的设计是最容易出问题的地方。每道题要有题目 ID、所属课程 ID、题型(单选/多选/填空/判断)、题干、选项(用 JSON 或分隔符存储)、正确答案、解析。题型字段决定了前端渲染方式,选项存储方式决定了查询和展示的效率。我见过有人把每个选项拆成单独的表,结果查询一道题要关联四五张表,性能很差。对于这种规模的项目,选项用 JSON 字符串存在一个字段里完全够用。
答题记录表记录每次答题的详情:记录 ID、用户 ID、题目 ID、用户答案、是否正确、答题时间。这张表的数据量增长最快,因为每个学生每做一道题就产生一条记录。索引要建在用户 ID 和答题时间上,方便后期做学习报告和错题统计。
2.3 项目分层与目录结构
一个能维护的 ASP.NET 项目不会把所有代码塞进一个文件夹。常见的分层方式是 Controller(控制器)、Model(数据模型)、View(视图)、DAL(数据访问层)、BLL(业务逻辑层)。Controller 只负责接收请求和返回响应,不直接操作数据库;BLL 处理业务规则,比如判断答案是否正确、计算得分;DAL 封装 SQL 查询和更新操作。
这种分层的好处是,当数据库从 SQL Server 换成其他数据库时,只需要改 DAL 层,Controller 和 BLL 基本不动。对于课程设计来说,分层还有一个实际好处——答辩时老师问「你的业务逻辑写在哪」,你能明确指出来,而不是说「都在.aspx.cs 里」。
目录结构上,我一般会这样组织:
/Controllers -- 控制器 /Models -- 实体类和数据上下文 /Views -- 视图页面 /Scripts -- JavaScript 文件 /Content -- CSS 和图片 /App_Data -- 数据库文件(如果用 LocalDB) /Helpers -- 工具类(加密、分页等)这个结构清晰,新人接手时能快速定位代码。如果项目用的是 ASP.NET Core,还会多一个Program.cs或Startup.cs用来配置中间件和服务注入。
3. 从零搭建开发环境与数据库
3.1 开发工具与运行环境清单
在动手写代码之前,先把环境搭好。这个项目需要的工具链不算复杂,但版本兼容性要注意。
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| Visual Studio | 2019 或 2022 社区版 | 免费,支持 ASP.NET 和 SQL Server 工具 |
| SQL Server | 2019 Express 或 LocalDB | Express 免费,LocalDB 更轻量 |
| .NET Framework | 4.7.2 或 4.8 | 如果用 ASP.NET Core 则用 .NET 6/8 |
| SSMS | 18.x 或更高 | 管理数据库的可视化工具 |
| IIS Express | VS 自带 | 开发时调试用,不需要单独装 IIS |
安装顺序建议先装 Visual Studio,安装时勾选「ASP.NET 和 Web 开发」工作负载,它会自动带上 SQL Server Express 和 IIS Express。如果已经装过 VS 但没勾选这个工作负载,打开 Visual Studio Installer 补上就行。
提示:如果电脑上已经装了完整版 SQL Server,安装 Express 版可能会冲突。这种情况下直接用已有的 SQL Server 实例,只需要在连接字符串里改服务器地址。
3.2 数据库创建与初始化脚本
环境就绪后,第一步是建数据库。打开 SSMS 连接到本地 SQL Server 实例,新建一个数据库,命名为EnglishLearningDB。然后执行建表脚本。下面是一个精简版的建表 SQL,覆盖了核心表:
-- 创建数据库(如果不存在) IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'EnglishLearningDB') BEGIN CREATE DATABASE EnglishLearningDB; END GO USE EnglishLearningDB; GO -- 用户表 CREATE TABLE Users ( UserId INT IDENTITY(1,1) PRIMARY KEY, UserName NVARCHAR(50) NOT NULL UNIQUE, PasswordHash NVARCHAR(128) NOT NULL, -- SHA256 哈希值 Salt NVARCHAR(32) NOT NULL, -- 每个用户独立的盐 Role NVARCHAR(20) NOT NULL DEFAULT 'Student', -- Student 或 Admin RegisterTime DATETIME NOT NULL DEFAULT GETDATE(), LastLoginTime DATETIME NULL ); -- 课程表 CREATE TABLE Courses ( CourseId INT IDENTITY(1,1) PRIMARY KEY, CourseName NVARCHAR(100) NOT NULL, Description NVARCHAR(500) NULL, CoverImage NVARCHAR(200) NULL, DifficultyLevel INT NOT NULL DEFAULT 1, -- 1初级 2中级 3高级 IsPublished BIT NOT NULL DEFAULT 0, CreateTime DATETIME NOT NULL DEFAULT GETDATE() ); -- 题目表 CREATE TABLE Questions ( QuestionId INT IDENTITY(1,1) PRIMARY KEY, CourseId INT NOT NULL FOREIGN KEY REFERENCES Courses(CourseId), QuestionType NVARCHAR(20) NOT NULL, -- SingleChoice, MultiChoice, FillBlank, TrueFalse Content NVARCHAR(1000) NOT NULL, Options NVARCHAR(2000) NULL, -- JSON 格式存储选项 CorrectAnswer NVARCHAR(500) NOT NULL, Explanation NVARCHAR(1000) NULL, CreateTime DATETIME NOT NULL DEFAULT GETDATE() ); -- 答题记录表 CREATE TABLE AnswerRecords ( RecordId INT IDENTITY(1,1) PRIMARY KEY, UserId INT NOT NULL FOREIGN KEY REFERENCES Users(UserId), QuestionId INT NOT NULL FOREIGN KEY REFERENCES Questions(QuestionId), UserAnswer NVARCHAR(500) NULL, IsCorrect BIT NOT NULL, AnswerTime DATETIME NOT NULL DEFAULT GETDATE() ); -- 在答题记录表上建索引,加速按用户和时间的查询 CREATE INDEX IX_AnswerRecords_UserId_Time ON AnswerRecords(UserId, AnswerTime DESC);这段脚本的逻辑很直接:先确保数据库存在,然后依次创建四张核心表。Users表的PasswordHash和Salt分开存储,是为了防止彩虹表攻击——即使两个用户密码相同,因为盐不同,哈希值也不同。Questions表的Options字段用 NVARCHAR(2000) 存 JSON,比如[{"key":"A","text":"apple"},{"key":"B","text":"banana"}],前端拿到后解析渲染,比拆成单独的表简单得多。
AnswerRecords表上的索引建在(UserId, AnswerTime DESC)上,因为最常见的查询是「查某个用户最近的答题记录」,这个索引能直接命中。如果后期要做错题本,再加一个(UserId, IsCorrect)的索引。
3.3 连接字符串配置与常见连接失败排查
数据库建好后,ASP.NET 项目需要通过连接字符串找到它。连接字符串通常写在Web.config(ASP.NET)或appsettings.json(ASP.NET Core)里。
Web.config 的配置方式:
<connectionStrings> <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=EnglishLearningDB;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /> </connectionStrings>Data Source=.表示本机默认实例,如果用的是 LocalDB,要改成Data Source=(LocalDB)\MSSQLLocalDB。Integrated Security=True表示用 Windows 身份验证,不需要输用户名密码。MultipleActiveResultSets=True允许在同一个连接上同时打开多个结果集,对于有嵌套查询的场景很有用。
连接失败是新手最容易翻车的地方。最常见的三种情况:一是Data Source写错,比如服务器实际是.\SQLEXPRESS却只写了.;二是数据库名称拼错,或者数据库还没创建;三是 Windows 账户没有访问数据库的权限。排查时先在 SSMS 里用同样的连接参数连一次,SSMS 能连上说明参数没问题,问题出在代码或权限配置上。
4. 核心功能模块的实现路径
4.1 用户注册登录与密码加密
注册登录是系统的入口,也是安全性最容易被忽视的地方。很多课程设计项目直接把密码明文存进数据库,这在答辩时会被扣分。正确的做法是生成随机盐,用 SHA256 对「密码+盐」做哈希,把哈希值和盐分别存两列。
// 密码加密工具类 public static class PasswordHelper { // 生成随机盐,长度 16 字节 public static string GenerateSalt() { byte[] saltBytes = new byte[16]; using (var rng = new RNGCryptoServiceProvider()) { rng.GetBytes(saltBytes); } return Convert.ToBase64String(saltBytes); } // 用 SHA256 对密码和盐做哈希 public static string HashPassword(string password, string salt) { using (var sha256 = SHA256.Create()) { string combined = password + salt; byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(combined)); return Convert.ToBase64String(hashBytes); } } // 验证密码:重新计算哈希并与存储值比对 public static bool VerifyPassword(string inputPassword, string storedHash, string storedSalt) { string inputHash = HashPassword(inputPassword, storedSalt); return inputHash == storedHash; } }这段代码的关键点在于:盐是每个用户独立的,注册时生成一次,和哈希值一起存进数据库。登录验证时,用用户输入的密码加上数据库里存的盐重新计算哈希,再和数据库里的哈希值比对。这样即使数据库泄露,攻击者也无法通过彩虹表反推出原始密码。
参数说明:GenerateSalt用RNGCryptoServiceProvider而不是Random,因为Random是可预测的,不适合安全场景。盐的长度 16 字节(128 位)足够,再长也不会显著提升安全性。HashPassword里把密码和盐拼接后再哈希,顺序无所谓,但注册和验证时必须一致。
登录成功后,用户信息通常存在 Session 里,后续请求通过 Session 判断是否已登录以及角色。ASP.NET 也可以用 Forms Authentication 的 Cookie 机制,但对于课程设计项目,Session 更直观,代码量也少。
4.2 课程列表与分页查询
学生登录后看到的第一个页面通常是课程列表。如果课程数量多,必须做分页,否则一次性加载所有课程会导致页面响应变慢。
分页查询在 SQL Server 里可以用OFFSET FETCH语法:
-- 查询第 2 页,每页 10 条,按创建时间倒序 SELECT CourseId, CourseName, Description, CoverImage, DifficultyLevel FROM Courses WHERE IsPublished = 1 ORDER BY CreateTime DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;OFFSET 10 ROWS表示跳过前 10 条,FETCH NEXT 10 ROWS ONLY表示取接下来的 10 条。页码和每页条数由前端传入,在 C# 里拼接参数时要用参数化查询,防止 SQL 注入。
// 分页查询课程列表 public List<Course> GetPublishedCourses(int pageIndex, int pageSize) { var courses = new List<Course>(); string sql = @"SELECT CourseId, CourseName, Description, CoverImage, DifficultyLevel FROM Courses WHERE IsPublished = 1 ORDER BY CreateTime DESC OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY"; using (var conn = new SqlConnection(connectionString)) using (var cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddWithValue("@Offset", (pageIndex - 1) * pageSize); cmd.Parameters.AddWithValue("@PageSize", pageSize); conn.Open(); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { courses.Add(new Course { CourseId = (int)reader["CourseId"], CourseName = reader["CourseName"].ToString(), Description = reader["Description"]?.ToString(), CoverImage = reader["CoverImage"]?.ToString(), DifficultyLevel = (int)reader["DifficultyLevel"] }); } } } return courses; }参数说明:pageIndex从 1 开始,pageSize一般设 10 到 20。@Offset的计算方式是(pageIndex - 1) * pageSize,这是分页的标准公式。用AddWithValue传参而不是字符串拼接,能有效防止 SQL 注入。
前端分页控件需要知道总记录数才能算出总页数,所以还要写一个GetPublishedCourseCount()方法执行SELECT COUNT(*)。这两个查询可以合并成一个存储过程,减少一次数据库往返。
4.3 在线答题与自动判分逻辑
答题模块是这个系统的核心交互。学生选择答案后提交,服务端判断对错并记录。不同题型的判分逻辑不同:单选题直接比对字符串;多选题要忽略顺序,把用户答案和正确答案都排序后再比;填空题要处理大小写和首尾空格;判断题本质上是单选题的特例。
// 判分逻辑,根据题型走不同分支 public bool CheckAnswer(Question question, string userAnswer) { if (string.IsNullOrWhiteSpace(userAnswer)) return false; switch (question.QuestionType) { case "SingleChoice": case "TrueFalse": // 单选和判断:直接比对,忽略大小写和空格 return string.Equals(userAnswer.Trim(), question.CorrectAnswer.Trim(), StringComparison.OrdinalIgnoreCase); case "MultiChoice": // 多选:拆分后排序再比对,忽略顺序 var userParts = userAnswer.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(p => p.Trim().ToUpper()).OrderBy(p => p); var correctParts = question.CorrectAnswer.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(p => p.Trim().ToUpper()).OrderBy(p => p); return userParts.SequenceEqual(correctParts); case "FillBlank": // 填空:忽略大小写和首尾空格 return string.Equals(userAnswer.Trim(), question.CorrectAnswer.Trim(), StringComparison.OrdinalIgnoreCase); default: return false; } }这段代码里,多选题的处理是重点。用户提交的答案可能是"A,C,B",正确答案是"A,B,C",直接比对会判错。所以先把两边都拆成数组、转大写、排序,再用SequenceEqual比对。填空题用OrdinalIgnoreCase忽略大小写,因为英语填空题里大小写通常不区分。
判分完成后,把结果写入AnswerRecords表,同时更新用户的答题统计。如果要做错题本,查询IsCorrect = 0的记录即可。
4.4 管理员后台的内容管理
管理员后台的功能相对直接:课程的增删改查、题目的批量导入、用户管理、学习数据统计。这里重点说题目批量导入,因为手动一道一道录入效率太低。
常见做法是提供一个 Excel 模板,管理员填好后上传,服务端解析 Excel 写入数据库。解析 Excel 可以用 EPPlus 或 NPOI 库。以 EPPlus 为例:
// 从上传的 Excel 文件批量导入题目 public int ImportQuestionsFromExcel(string filePath, int courseId) { int successCount = 0; using (var package = new ExcelPackage(new FileInfo(filePath))) { var worksheet = package.Workbook.Worksheets[0]; // 取第一个工作表 int rowCount = worksheet.Dimension.Rows; for (int row = 2; row <= rowCount; row++) // 从第 2 行开始,第 1 行是表头 { string type = worksheet.Cells[row, 1].Text.Trim(); string content = worksheet.Cells[row, 2].Text.Trim(); string options = worksheet.Cells[row, 3].Text.Trim(); string answer = worksheet.Cells[row, 4].Text.Trim(); string explanation = worksheet.Cells[row, 5].Text.Trim(); if (string.IsNullOrEmpty(content) || string.IsNullOrEmpty(answer)) continue; // 跳过空行 // 插入数据库 InsertQuestion(courseId, type, content, options, answer, explanation); successCount++; } } return successCount; }参数说明:filePath是上传文件保存到服务器后的物理路径,courseId指定这批题目属于哪门课程。Excel 的列顺序要和模板一致,第 1 列题型、第 2 列题干、第 3 列选项(JSON 格式)、第 4 列正确答案、第 5 列解析。导入时跳过题干或答案为空的行,避免脏数据。
注意:上传的 Excel 文件要限制大小和格式,只允许
.xlsx,并且在解析前检查文件是否损坏。生产环境还要考虑并发导入的问题,但课程设计项目一般不需要。
5. 部署上线与避坑排查
5.1 IIS 部署的完整步骤
开发完成后,把项目部署到 IIS 上才能让其他人在浏览器里访问。部署流程分几步:先在 Visual Studio 里右键项目选择「发布」,目标选「文件系统」,发布到一个文件夹;然后在 IIS 管理器里新建网站,物理路径指向发布文件夹,绑定端口(比如 8080);最后确保应用程序池的 .NET 版本和项目一致。
如果项目用的是 .NET Framework 4.7.2,应用程序池要选「.NET CLR Version v4.0.30319」,托管管道模式用「集成」。如果用的是 ASP.NET Core,则需要安装 ASP.NET Core Hosting Bundle,应用程序池的 .NET CLR 版本选「无托管代码」。
数据库权限也要注意。IIS 应用程序池的默认身份是ApplicationPoolIdentity,这个身份默认没有 SQL Server 的访问权限。需要在 SSMS 里给IIS APPPOOL\你的应用程序池名称这个登录名授予数据库的db_datareader和db_datawriter角色。或者更简单的方式,在连接字符串里用 SQL Server 身份验证,指定用户名和密码。
5.2 五个高频翻车现场与修复方法
现象一:页面报「无法打开登录所请求的数据库」。原因是连接字符串里的数据库名称和实际不符,或者数据库服务没启动。解决方法是打开 SSMS 确认数据库存在且能连接,检查连接字符串的Initial Catalog值,确认 SQL Server 服务(MSSQLSERVER 或 SQLEXPRESS)在 Windows 服务里是运行状态。
现象二:CSS 和图片加载不出来,页面样式全乱。原因是 IIS 没有配置静态文件的 MIME 类型,或者发布时Content文件夹没被包含。解决方法是检查发布文件夹里是否有Content目录,在 IIS 里确认.css和.png的 MIME 类型已注册。ASP.NET Core 项目还需要在Program.cs里调用app.UseStaticFiles()。
现象三:登录后跳转回登录页,Session 丢失。原因是应用程序池回收导致 Session 丢失,或者 Cookie 配置有问题。解决方法是把 Session 模式改为StateServer或SQLServer(在 Web.config 的<sessionState>节点配置),或者在 IIS 里把应用程序池的「闲置超时」设为 0(不回收)。对于课程设计项目,最简单的办法是在 Web.config 里设置<sessionState timeout="120">,延长超时时间。
现象四:答题提交后页面卡死或报 500 错误。原因通常是 SQL 语句有语法错误,或者参数类型不匹配。解决方法是打开 Visual Studio 的「输出」窗口看详细异常信息,或者在 Web.config 里把<customErrors mode="Off"/>打开,让浏览器显示完整错误堆栈。常见的是AddWithValue传了null值导致参数类型推断失败,改成DBNull.Value即可。
现象五:多选题判分总是错误。原因是用户答案和正确答案的分隔符不一致,比如一个用逗号一个用分号。解决方法是在判分前统一分隔符,把分号替换成逗号再拆分。另外要确认前端提交的答案顺序和格式,可以在判分方法里加日志输出,对比用户答案和正确答案的原始值。
5.3 性能与安全的最低限度检查
课程设计项目虽然不需要扛高并发,但有几个底线要守住。SQL 查询必须参数化,杜绝字符串拼接;密码必须哈希存储,不能明文;上传文件要限制类型和大小,防止上传可执行文件;管理员后台的每个操作都要验证 Session 中的角色,不能只靠前端隐藏菜单。
性能方面,给常用的查询字段建索引(比如Users.UserName、AnswerRecords.UserId),避免在循环里查数据库(把多次查询合并成一次IN查询),页面上的静态资源启用浏览器缓存。这些措施花不了多少时间,但能让系统在演示时流畅很多。
6. 让项目从「能跑」到「能讲」的几个技巧
答辩或验收时,老师最常问的三个问题是:你的架构为什么这样设计、数据库表之间的关系是什么、某个功能的具体实现逻辑是什么。如果只是把代码跑起来,回答这些问题会很吃力。我的习惯是在开发过程中随手记一份「决策日志」,每做一个技术选择就写两句话:选了什么、为什么选它、放弃了什么替代方案。比如「用 Session 而不是 JWT,因为项目是服务端渲染,Session 更简单,不需要额外处理 Token 刷新」。这份日志在答辩前翻一遍,比临时背代码有效得多。
另一个技巧是准备一个「最小可演示数据集」。系统里不要只放一两条测试数据,而是准备 3 门课程、每门 10 道题、2 个学生账号和 1 个管理员账号。演示时先以学生身份登录,做几道题,展示判分和记录;再以管理员身份登录,展示课程管理和题目导入。整个流程控制在 5 分钟内,覆盖所有核心功能。数据提前在数据库里插好,不要现场录入。
如果想让项目更有说服力,可以加一个简单的学习统计页面,用 SQL 的GROUP BY和COUNT算出每个学生的答题正确率、每门课程的平均分。这个功能代码量不大,但能让评委看到数据汇总的能力。查询语句大概是这样:
-- 统计每个学生的答题正确率 SELECT u.UserName, COUNT(*) AS TotalAnswers, SUM(CASE WHEN ar.IsCorrect = 1 THEN 1 ELSE 0 END) AS CorrectAnswers, CAST(SUM(CASE WHEN ar.IsCorrect = 1 THEN 1 ELSE 0 END) AS FLOAT) / COUNT(*) AS AccuracyRate FROM AnswerRecords ar INNER JOIN Users u ON ar.UserId = u.UserId GROUP BY u.UserName ORDER BY AccuracyRate DESC;这个查询用CASE WHEN把布尔值转成 0 和 1 再求和,得到正确题数,除以总题数就是正确率。CAST AS FLOAT是为了避免整数除法导致结果永远是 0 或 1。把这个查询的结果渲染成一个表格或简单图表,答辩时的演示效果会好很多。
最后说一个我踩过的坑:不要等到答辩前一天才部署到 IIS。本地 Visual Studio 调试和 IIS 部署是两套环境,连接字符串、权限、路径都可能出问题。提前一周在目标机器上部署一次,把问题暴露出来,留足修复时间。希望帮到你。
本文还有配套的精品资源,点击获取