十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C#班级通讯录管理系统实训代码解析:OleDb、DataSet与WinForms实战

C#班级通讯录管理系统实训代码解析:OleDb、DataSet与WinForms实战 简介C#班级通讯录管理系统实训报告是一份面向C#初学者的实践教学文档完整呈现了利用Visual Studio 2005与.NET Framework开发班级通讯录系统的全过程。报告以2013年春季学期实训为背景涵盖实训主题、目的要求、重要知识点和具体实现步骤并从系统总体结构设计、功能模块划分、流程图绘制和数据库表结构设计入手围绕显示、查询、添加、修改、删除等核心功能详细讲解了ADO.NET中.NET Framework数据提供程序与DataSet两大组件的使用方法以及如何通过OleDb连接Access数据库。资源包内仅含1个doc文档大小551KB已有138人下载学习。文档还给出了登录模块与主界面设计思路数据库字段包括学号、姓名、班级、性别、年龄、电话、地址、邮政编码和邮箱等并附有基于System.Data.OleDb的完整代码示例覆盖连接字符串定义、数据集获取与SQL命令执行等典型操作。整份报告结构清晰、代码可直接参考对于完成课程设计、复习C#数据库编程或编写同类实训报告都具有实用价值。1. 一份 C# 班级通讯录实训报告为什么值得拆开看2013 年的 Visual Studio 2005 加 Access 组合放在今天看像是上个时代的东西但这套《C#班级通讯录管理系统实训报告》恰恰是大量 C# 老项目的缩影OleDb 连接、DataSet 离线数据、WinForms 窗体跳转、字符串拼 SQL。你如果正在维护一套十年前遗留的 C# 教务系统或者刚接手一个用 Access 当库的小工具这份报告里的代码就是你最先遇到的形态。报告本身是课程作业结构总体图、流程图、数据库设计、逐窗体代码但把它当成代码仓库来读能看到一条清晰的主线DataAccess 类做数据库统一入口登录窗体做身份校验主窗体用 MenuStrip 路由到功能窗体增删改查分布在三个窗体里。下面按这条主线逐段拆解顺带指出哪些写法能直接抄哪些必须在真实项目里改掉。2. 数据访问层OleDb 连接封装与 DataSet 取数的取舍把数据库操作集中在 DataAccess 类里是这份报告最值得保留的做法。数据访问层独立之后后续加窗体只需要DataAccess data new DataAccess(); data.dataCon();就能在任意位置拿到连接和数据不需要每处新写一遍连接逻辑。2.1 连接字符串与 Jet 数据库引擎的坑报告把连接定义放在dataCon()方法里指向程序运行目录下的 Access 文件private string strDSN; OleDbConnection oledbCon; public void dataCon() { strDSN ProviderMicrosoft.Jet.OLEDB.4.0;Data Source Application.StartupPath.ToString() \\class.mdb; oledbCon new OleDbConnection(strDSN); }ProviderMicrosoft.Jet.OLEDB.4.0指定的是 Jet 引擎负责读写 Access 2003 及更早版本的 .mdb 文件。Data Source后接物理文件路径这里用Application.StartupPath拼相对路径意味着 class.mdb 必须和 exe 在同一目录否则连接直接失败。这是 Access 程序最常见的部署问题发布时漏掉数据库文件的现象非常普遍后面会专门讲验证方法。注意一个隐性问题dataCon()没有返回值也不检查oledbCon是否成功创建调用方必须保证先执行它再执行其它方法。后面所有窗体的代码都遵循data.dataCon(); data.getDataset(strSql);的固定顺序一旦漏掉就会抛 NullReferenceException。2.2 getDataset 与 DataSet 的选型理由查询方法用 OleDbDataAdapter 填充 DataSetpublic DataSet getDataset(string sql) { DataSet ds new DataSet(); oledbCon.Open(); try { OleDbCommand oledbCom new OleDbCommand(sql, oledbCon); OleDbDataAdapter oledbDa new OleDbDataAdapter(oledbCom); oledbDa.Fill(ds); return ds; } catch (Exception ex) { throw new Exception(ex.ToString()); } finally { oledbCon.Close(); } }执行顺序是打开连接、创建 OleDbCommand 承载 SQL、用 OleDbDataAdapter.Fill 填数据、finally 里关连接。finally 是必须的不管查询成功还是抛异常连接都要归还给连接池。这里不用 DataReader 而选 DataSet背后是绑定场景的考虑对比点DataSetDataReader数据形态内存中的离线数据集只读向前的数据库游标连接占用Fill 后可断开需保持连接直到读取完多表支持支持多个 DataTable 与关系单结果流绑定 DataGridView可直接作为 DataSource需要逐行转 DataTable适用场景窗体频繁开关、数据回显轻量快速读取实训系统每个窗体都要把结果绑定到 DataGridViewDataSet 取数后立刻 Close 连接在多窗体频繁切换时更不容易造成连接泄漏。2.3 sqlExec 的参数与双层异常处理写操作方法同样值得推敲public bool sqlExec(string sql) { try { oledbCon.Open(); } catch { MessageBox.Show(数据库未连接); } try { OleDbCommand oledbCom new OleDbCommand(sql, oledbCon); oledbCom.ExecuteNonQuery(); return true; } catch (Exception ex) { MessageBox.Show(ex.Message, 提示); return false; } finally { oledbCon.Close(); } }ExecuteNonQuery用于执行 INSERT、UPDATE、DELETE 这类不返回结果集的命令返回受影响行数。这里用两个 try/catch 分开处理外层捕获连接失败内层捕获 SQL 执行错误。但从排错角度看不理想连接失败和 SQL 失败的提示在界面上区分度太低。实践做法是把外层 catch 改成throw new Exception(数据库连接失败请检查 class.mdb 是否就位, ex)让日志里能直接定位阶段。3. 登录与主界面WinForms 窗体传参和菜单路由的常见写法登录窗体承担整个程序的入口校验button1_Click 先检查两个文本框非空再查 userslogin 表确认身份。3.1 登录校验逻辑与三个边界核心代码如下private void button1_Click(object sender, EventArgs e) { string username, password; string strSql ; DataSet ds; if (textBox1.Text.Trim() ! textBox2.Text.Trim() ! ) { username textBox1.Text.Trim(); password textBox2.Text.Trim(); strSql select * from userslogin where userId username and userPwd password ; DataAccess data new DataAccess(); data.dataCon(); ds data.getDataset(strSql); if (ds.Tables[0].Rows.Count 1) { Main fMain new Main(); fMain.Show(); this.Hide(); } else { MessageBox.Show(用户名或密码错误, 登录失败); } } }判定逻辑是行数为 1 即成功.Trim()把首尾空格去掉这属于 WinForms 里基础的防御性写法。三个值得注意的边界第一字符串拼接 SQL输入 or 11这类内容时登录校验会被绕过这是典型注入入口下一章专门展开。第二登录成功后用fMain.Show()非模态显示登录窗体this.Hide()隐藏而不 Close。一旦 Close登录窗体资源被释放主窗体的 Application 消息循环可能受影响。好在这里主窗体关闭时调用了Application.Exit()强制结束进程小工具里可接受但不优雅。C# 窗体生命周期管理在真实项目中通常会引入一个 Program.cs 层的全局导航控制。第三UsersLogin_Activated事件里调用textBox1.Focus()把光标定位到用户名输入框这类小交互在实训代码里很少见算是作者主动加的体验优化。3.2 主界面 MenuStrip 到功能窗体的路由主界面代码不含业务逻辑全部是菜单事件路由private void 添加联系人ToolStripMenuItem_Click(object sender, EventArgs e) { AddLinkman frm2 new AddLinkman(); frm2.Show(); } private void 删除联系人ToolStripMenuItem_Click(object sender, EventArgs e) { ManageLinkman frm4 new ManageLinkman(); frm4.Show(); } private void 修改联系人ToolStripMenuItem_Click(object sender, EventArgs e) { ManageLinkman frm3 new ManageLinkman(); frm3.Show(); }删除、修改、查询三个菜单都打开同一个 ManageLinkman 窗体这是有意义的设计决策三者第一步都是显示联系人列表并定位目标记录后续动作由窗体内的按钮触发。与其复制三个近乎相同的列表窗体不如一个窗体承载三种操作。事件方法名和菜单项一一对应是设计器自动生成的自己手写 MenuStrip 时双击菜单项就会跳转到 Click 事件不需要手动挂委托。窗口实例变量名 frm3/frm4 不一致只是命名习惯问题不影响运行。4. 增删改查落地条件拼接、DataGridView 与 SQL 注入边界ManageLinkman 是整份代码里信息量最大的窗体同时承担条件查询、删除选中行、把选中行转给修改窗体三个职责。4.1 条件组合查询与 where 11 写法查询按钮的核心是动态拼接条件string conditon ; if (textBox1.Text ! ) { conditon and stuNo textBox1.Text ; } if (textBox2.Text ! ) { conditon and stuName textBox2.Text ; } if (textBox3.Text ! ) { conditon and classId textBox3.Text ; } if (comboBox1.Text ! ) { conditon and Sex comboBox1.Text ; } strSql select stuNo as 学号, stuName as 姓名, Sex as 性别, birthday as 出生日期, classId as 班级, tel as 电话, address as 家庭地址, postalcode as 邮政编码, email as 电子邮箱, remark as 备注 from usersinfo where 11 conditon;两个关键点。第一是列别名查询列全部用as 中文别名重命名DataGridView 绑定后表头直接显示“学号、姓名、性别”省去手动设置列标题的步骤这是数据展示很省事的做法代价是 SQL 里字段名和界面列名之间的映射关系需要维护。第二是where 11恒真条件后面每个分支统一用and前缀拼接不需要判断是否是第一个条件动态查询的经典写法性能影响可以忽略优化器会直接处理掉。但拼接方式本身有问题。所有输入都用单引号包住输入含单引号就改变 SQL 语义。比如姓名框输入张三 or 11条件变成stuName张三 or 11整表被返回。数据量小看不出问题生产环境就是标准的 SQL 注入入口。改成参数化也不复杂strSql select stuNo as 学号, stuName as 姓名, Sex as 性别, birthday as 出生日期, classId as 班级, tel as 电话, address as 家庭地址, postalcode as 邮政编码, email as 电子邮箱, remark as 备注 from usersinfo where 11 and stuNostuNo and stuNamestuName; OleDbCommand cmd new OleDbCommand(strSql, oledbCon); cmd.Parameters.Add(stuNo, OleDbType.VarChar).Value textBox1.Text.Trim(); cmd.Parameters.Add(stuName, OleDbType.VarChar).Value textBox2.Text.Trim();注意 OleDb 参数占位符同样是名称但参数只能按位置绑定名称不能复用。如果同一 SQL 里两次出现stuNameOleDb 会按出现顺序传相同索引的参数这与 SqlClient 的行为有明显差异迁移数据库时要格外留意。提示OleDb 参数不支持像 SqlClient 那样按名复用同一个参数名出现两次会把第二个值覆盖到第一个位置排查时优先怀疑参数顺序。4.2 删除、修改与静态属性跨窗体传值删除按钮直接取当前选中行第一列的值拼 DELETEstring strSql; DataAccess data new DataAccess(); strSql delete from usersinfo where stuNo dataGridView1.CurrentRow.Cells[0].Value.ToString() ; data.dataCon(); if (data.sqlExec(strSql)) { MessageBox.Show(删除成功); } else { MessageBox.Show(删除失败); }dataGridView1.CurrentRow.Cells[0].Value取的是当前选中行第一列单元格值查询结果第一列是 stuNo所以拿到的是学号。执行删除后界面不会自动刷新需要重新点一次查询按钮或手动再次调用查询逻辑这是个使用细节。修改按钮通过静态属性跨窗体传值public static string stuNo; public static string StuNo { get { return stuNo; } set { stuNo value; } } // 在 ManageLinkman 按钮事件中 ManageLinkman.StuNo dataGridView1.CurrentRow.Cells[0].Value.ToString(); EditLinkman s1 new EditLinkman(); s1.Show();这是实训代码里最值得学习的设计点。静态属性 StuNo 生命周期是整个进程不随窗体实例销毁因此值能在 ManageLinkman 和 EditLinkman 之间可靠传递。代价是全局可见性两个窗体同时操作时会互相覆盖比事件委托或构造函数传参更脆弱。小工具里这样做没问题但 C# 高级编程里通常会考虑改成事件驱动或使用窗体间数据上下文以便控制访问范围。4.3 添加窗体与表单验证粒度添加联系人的 INSERT 语句strSql insert into usersinfo(stuNo,stuName,classId,birthday,tel,postalcode,email,address,remark,Sex) values ( textBox1.Text , textBox2.Text , textBox3.Text , textBox4.Text , textBox5.Text , textBox6.Text , textBox7.Text , textBox8.Text , textBox9.Text , comboBox1.Text );字段顺序和 values 顺序一一对应。这里暴露的问题是表单验证粒度过粗只判断文本框非空没有判断学号是否已存在。如果数据库没有给 stuNo 设主键重复数据会直接插入所以实训里应该把 stuNo 设为主键或者在添加前先执行一次存在性检查。4.4 实训代码里的两处典型 SQL 错误修改窗体的 UPDATE 语句里藏着两个问题第一处是表名拼写strSql update uesrsinfo set ... where stuNo ManageLinkman.stuNo ;uesrsinfo是usersinfo的错误键入。因为用的是字符串拼接拼出的 SQL 在运行时才报“表名无效”编译器不会提前发现。这类错误在实训代码里很典型最可靠的排查方式是把拼出来的 strSql 弹窗显示或写进日志看实际 SQL 再对表名。第二处是末位字段闭合后多了逗号... email textBox7.Text ,remark textBox9.Text ,where stuNo ...remark字段值闭合后多出,where直接语法报错。拿到这份 doc 时要先通读所有 SQL把明显错误的逗号和表名清掉再运行这是照抄实训代码前的基本功课。5. 把 Access 换成 SQL ServerOleDb 到 SqlClient 的迁移技巧数据访问层全部基于 OleDb换数据库改造成本不大因为业务窗体只依赖 DataAccess 的方法签名连接字符串和数据提供程序是主要变化点。5.1 连接字符串与类型适配对比两种连接的写法// Access (Jet) ProviderMicrosoft.Jet.OLEDB.4.0;Data Source Application.StartupPath \\class.mdb // SQL Server 2008 用 SqlClient Server.;DatabaseClassDB;User Idsa;Password你的密码;Provider 和 Data Source 换成 Server 和 DatabaseOleDbConnection 换成 SqlConnection。如果不想逐窗体改代码可以只在 DataAccess 内部替换。换完后有一个容易忽略的差异Jet 里日期用#2024-01-01#包裹SQL Server 是2024-01-01。原报告 birthday 直接拿文本框字符串拼 SQL在 Access 宽松类型转换下能运行SQL Server 会更严格。5.2 连接自检与字段级验证迁移后建议写一个自检方法放在窗体 Load 事件里确认数据库文件在不在public bool CheckConnection() { try { dataCon(); oledbCon.Open(); using (OleDbCommand cmd new OleDbCommand(select count(*) from usersinfo, oledbCon)) { int count (int)cmd.ExecuteScalar(); return count 0; } } catch { return false; } finally { oledbCon.Close(); } }ExecuteScalar返回第一行第一列的值count(*) 拿到的就是联系人总数。这个自检能同时验证连接串、文件路径和表是否存在日志里记录一条连接状态。字段适配还有两项要注意Access 的“是/否”字段绑到 DataGridView 后显示 True/False需要在列格式化事件里转成“是/否”Access 的 memo 类型对应 SQL Server 的 ntext 或 nvarchar(max)Jet 对末尾空格会做截断SQL Server 不会where tel13801380000这类等值查询在两边结果可能不同。验收检查点放在三个位置按学号、姓名、性别组合查询能否精确命中修改后值是否在列表里更新删除后行数是否减少。这三个检查点对应用户对增删改查最直接的预期走完一遍四个基础模块的回归就完成了。本文还有配套的精品资源点击获取
返回列表