手把手教你用C# WinForms + ADO.NET实现学员信息管理(增删改)
一、项目概述
本程序实现了一个基于SQL Server数据库的学员信息管理工具,主要功能包括:
-
添加学员:录入编号、姓名、性别、年龄
-
修改学员:根据学员编号修改其性别和年龄
-
删除学员:支持按姓名删除、按编号删除
界面使用WinForms设计,分为三个区域,如下图:

二、整体思路
拿到需求后,我的设计步骤如下:
-
数据库设计:创建
stuInfo表,包含stuNo(学员编号,主键)、stuName、stuSex、stuAge四个字段。 -
界面布局:用Panel分区,使用TextBox输入文本,ComboBox选择年龄(15-30岁),RadioButton选择性别。
-
数据操作:采用ADO.NET的
SqlConnection、SqlCommand,编写SQL语句实现增删改。 -
异常处理与验证:对用户输入做非空校验,操作前先查询数据是否存在,避免直接操作失败。
三、准备工作
-
IDE:Visual Studio 2019/2022
-
.NET版本:.NET Framework 4.5+
-
数据库:SQL Server 2012+(本例使用本地实例
server=.) -
数据库表脚本:
CREATE DATABASE student;
GO
USE student;
GO
CREATE TABLE stuInfo (
stuNo NVARCHAR(20) PRIMARY KEY,
stuName NVARCHAR(50) NOT NULL,
stuSex NCHAR(1) CHECK(stuSex IN ('男','女')),
stuAge INT CHECK(stuAge BETWEEN 15 AND 30)
);
GO
四、核心代码解析
1. 窗体加载 – 初始化年龄下拉框
在Form1_Load事件中,为两个年龄ComboBox动态添加15~30的数字。
private void Form1_Load(object sender, EventArgs e)
{
// 添加学员区的年龄下拉框
for (int i = 15; i <= 30; i++)
{
comboBox_age.Items.Add(i);
}
comboBox_age.SelectedIndex = 0; // 默认选中15
// 修改学员区的年龄下拉框
for (int i = 15; i <= 30; i++)
{
comboBox_exAge.Items.Add(i);
}
}
思路:固定范围选择避免了用户输入非法年龄。
2. 添加学员 – 完整业务流程
步骤:
-
非空校验(编号、姓名、性别)
-
从控件取值,年龄需转为
int -
连接数据库执行
INSERT -
成功后清空表单
关键代码:
private void button_add_Click(object sender, EventArgs e)
{
// 1. 非空判断
if (string.IsNullOrWhiteSpace(textBox_ID.Text))
{
MessageBox.Show("请输入学员编号!");
return;
}
// ... 姓名、性别校验(性别必须二选一)
string stuId = textBox_ID.Text;
string stuName = textBox_name.Text;
string stuSex = radioB_man.Checked ? "男" : "女";
int stuAge = Convert.ToInt32(comboBox_age.SelectedItem);
// 2. 数据库插入
using (SqlConnection con = new SqlConnection(@"server=.;uid=sa;pwd=123;database=student"))
{
con.Open();
string sql = $"INSERT INTO stuInfo VALUES ('{stuId}','{stuName}','{stuSex}',{stuAge})";
using (SqlCommand cmd = new SqlCommand(sql, con))
{
int result = cmd.ExecuteNonQuery();
if (result > 0)
{
MessageBox.Show("添加成功");
ClearAddForm(); // 自定义清空方法
}
else
MessageBox.Show("添加失败");
}
}
}
⚠️ 注意:代码中性别获取逻辑存在隐患 – 若两个RadioButton都未选中,会默认“女”。实际应该先判断,提示用户选择。我后来优化成了if-else结构。
3. 修改学员 – 先查后改
修改的核心思路:根据用户输入的编号,先查询数据库中是否存在该学员,若存在再执行UPDATE。
private void button_exchange_Click(object sender, EventArgs e)
{
// 非空校验
if (string.IsNullOrWhiteSpace(textBox_exID.Text))
{
MessageBox.Show("请输入要修改的学员编号!");
return;
}
string exstuID = textBox_exID.Text;
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
// 第一步:查是否存在
string checkSql = $"SELECT COUNT(*) FROM stuInfo WHERE stuNo='{exstuID}'";
using (SqlCommand checkCmd = new SqlCommand(checkSql, con))
{
int count = (int)checkCmd.ExecuteScalar();
if (count == 0)
{
MessageBox.Show("查询不到此学员编号!");
return;
}
}
// 第二步:获取新值(性别、年龄)
string newSex = radioB_exMan.Checked ? "男" : "女";
int newAge = Convert.ToInt32(comboBox_exAge.SelectedItem);
// 第三步:更新
string updateSql = $"UPDATE stuInfo SET stuSex='{newSex}', stuAge={newAge} WHERE stuNo='{exstuID}'";
using (SqlCommand cmd = new SqlCommand(updateSql, con))
{
int result = cmd.ExecuteNonQuery();
if (result > 0)
{
MessageBox.Show("修改成功!");
ClearModifyForm();
}
else
MessageBox.Show("修改失败!");
}
}
}
4. 删除学员 – 按姓名 / 按编号
两个删除逻辑高度相似:校验非空 → 验证存在 → 执行DELETE。以按姓名删除为例:
private void button_delName_Click_1(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(textBox_delName.Text))
{
MessageBox.Show("请输入要删除的姓名!");
return;
}
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
// 验证姓名是否存在
string checkSql = $"SELECT COUNT(*) FROM stuInfo WHERE stuName='{textBox_delName.Text}'";
using (SqlCommand cmd = new SqlCommand(checkSql, con))
{
int count = (int)cmd.ExecuteScalar();
if (count == 0)
{
MessageBox.Show("你输入的姓名不存在!");
return;
}
}
// 执行删除(注意:会删除所有同名的记录!)
string delSql = $"DELETE FROM stuInfo WHERE stuName='{textBox_delName.Text}'";
using (SqlCommand cmd = new SqlCommand(delSql, con))
{
int count = cmd.ExecuteNonQuery();
if (count > 0)
MessageBox.Show("删除成功!");
}
}
}
按编号删除代码类似,这里不再重复。
五、开发中遇到的问题 & 反思
🔴 问题1:SQL注入风险
整个项目中使用的是字符串拼接SQL,例如:
$"SELECT COUNT(*) FROM stuInfo WHERE stuNo='{exstuID}'"
如果用户在文本框输入 ' OR '1'='1,后果不堪设想。这是严重的安全隐患。
✅ 解决方案:使用参数化查询。例如:
string sql = "INSERT INTO stuInfo VALUES (@no,@name,@sex,@age)";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("@no", stuId);
// ... 其他参数
🔴 问题2:数据库连接字符串硬编码
代码中直接写死了server=.;uid=sa;pwd=123;database=student,一旦数据库密码或服务器变更,必须重新编译程序。
✅ 改进:将连接字符串写入App.config配置文件,通过ConfigurationManager读取。
🔴 问题3:控件事件绑定错误
设计文件中,button3被命名为“修改”按钮,却绑定了button_exchange_Click事件(这个事件是修改学员区的)。这是个明显的复制粘贴错误。
✅ 修正:删除button3或为其编写正确的删除逻辑。
🔴 问题4:删除后未清空输入框
添加/修改成功后清空了表单,但删除成功后没有清空对应的文本框,用户体验欠佳。
✅ 改进:在删除成功后调用textBox_delName.Clear()等。
🔴 问题5:年龄获取时的类型转换
代码中使用Convert.ToInt32(comboBox_age.SelectedItem),但如果用户未选择(SelectedItem为null),会抛出异常。虽然我初始化时设置了SelectedIndex=0,但严谨起见应该判断。
✅ 优化:
if (comboBox_age.SelectedItem == null || !int.TryParse(comboBox_age.SelectedItem.ToString(), out int age))
{
MessageBox.Show("请选择有效年龄!");
return;
}
🔴 问题6:数据库连接未显式关闭
代码中多处写了con.Close(),但实际上using块结束时会自动释放并关闭连接,无需手动调用。手动调用也可能引发二次释放问题。
✅ 建议:去掉所有显式的Close(),依赖using即可。
六、总结
通过这个小项目,我们实践了WinForms的常用控件用法、ADO.NET的核心对象(Connection、Command、ExecuteNonQuery/ExecuteScalar)以及数据库的增删改基本操作。同时也暴露了代码中常见的几个坑:
-
忘记校验性别是否选中
-
忽略SQL注入风险
-
事件绑定错乱
-
资源管理可以更优雅
收获:以后写数据库交互代码,我会默认使用参数化查询 + 配置文件存储连接字符串 + 完善的输入验证。希望这篇博客也能让正在学习C#数据库编程的你少走一些弯路。
如果你有任何疑问或发现了其他bug,欢迎在评论区交流讨论!
更多推荐

所有评论(0)