在WinForm应用程序开发中,数据持久化是每个开发者必须掌握的基础技能。今天我要分享的是一个典型的用户管理系统实现方案,使用C#语言配合SQL Server数据库完成用户信息的添加和删除功能。这个案例虽然基础,但涵盖了从数据库设计到界面交互的完整流程,是理解ADO.NET数据操作的最佳入门实践。
这个系统需要实现两个核心功能:
整个项目会涉及以下几个关键技术点:
合理的数据库设计是系统稳定运行的基础。在这个用户管理系统中,我设计了两张核心表:
UserRole(用户角色表)
sql复制CREATE TABLE UserRole (
RoleId INT PRIMARY KEY,
RoleName NVARCHAR(50) NOT NULL
);
SysAdmin(用户信息表)
sql复制CREATE TABLE SysAdmin (
LoginId INT IDENTITY(1,1) PRIMARY KEY,
LoginName NVARCHAR(50) NOT NULL,
LoginPwd NVARCHAR(100) NOT NULL,
RoleId INT NOT NULL,
FOREIGN KEY (RoleId) REFERENCES UserRole(RoleId)
);
注意:在实际项目中,密码字段应该存储加密后的值而非明文,这里为了演示简化处理。
在系统使用前,需要先初始化角色数据。执行以下SQL语句插入基础角色:
sql复制INSERT INTO UserRole(RoleId, RoleName)
VALUES
(1, '管理员'),
(2, '工程师'),
(3, '操作员');
这个初始化步骤非常重要,因为SysAdmin表中的RoleId字段通过外键关联到UserRole表,如果尝试插入不存在的RoleId会导致数据库报错。
用户界面采用经典的WinForm设计,包含以下核心控件:
| 控件类型 | 控件名称(Name) | 用途说明 |
|---|---|---|
| TextBox | txt_LoginName | 输入用户名 |
| TextBox | txt_LoginPwd | 输入密码 |
| ComboBox | cmb_RoleName | 选择用户角色 |
| Button | btn_ADD | 执行添加操作 |
| Button | btn_DELET | 执行删除操作 |
界面布局建议采用TableLayoutPanel或简单的流式布局(FlowLayoutPanel),确保在不同分辨率下都能正常显示。
ComboBox控件的配置需要特别注意:
这样配置后,ComboBox的SelectedIndex属性会对应选项的索引位置(从0开始),我们可以通过这个索引值+1来获取对应的RoleId。
首先需要在项目中配置数据库连接字符串。建议将连接字符串放在配置文件中:
csharp复制// 在App.config中添加
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=.;Initial Catalog=UserDB;Integrated Security=True"
providerName="System.Data.SqlClient"/>
</connectionStrings>
// 在代码中读取
string connStr = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
添加用户的完整代码实现如下:
csharp复制private void btn_ADD_Click(object sender, EventArgs e)
{
// 1. 输入验证
if(string.IsNullOrWhiteSpace(txt_LoginName.Text) ||
string.IsNullOrWhiteSpace(txt_LoginPwd.Text))
{
MessageBox.Show("用户名和密码不能为空");
return;
}
try
{
// 2. 创建连接
using(SqlConnection sqlConnection = new SqlConnection(connStr))
{
// 3. 参数化SQL语句(防止SQL注入)
string sql = "INSERT INTO SysAdmin(LoginName,LoginPwd,RoleId) VALUES(@name,@pwd,@roleId)";
// 4. 创建命令对象并添加参数
SqlCommand sqlCommand = new SqlCommand(sql, sqlConnection);
sqlCommand.Parameters.AddWithValue("@name", txt_LoginName.Text);
sqlCommand.Parameters.AddWithValue("@pwd", txt_LoginPwd.Text);
sqlCommand.Parameters.AddWithValue("@roleId", cmb_RoleName.SelectedIndex + 1);
// 5. 执行操作
sqlConnection.Open();
int rowsAffected = sqlCommand.ExecuteNonQuery();
if(rowsAffected > 0)
MessageBox.Show("用户添加成功");
else
MessageBox.Show("添加失败");
}
}
catch(Exception ex)
{
MessageBox.Show($"发生错误: {ex.Message}");
}
}
重要改进:原始代码使用字符串拼接SQL语句,存在SQL注入风险。这里改用参数化查询,这是实际项目中的必备安全措施。
删除功能的实现同样需要注意安全性和健壮性:
csharp复制private void btn_DELET_Click(object sender, EventArgs e)
{
if(string.IsNullOrWhiteSpace(txt_LoginName.Text))
{
MessageBox.Show("请输入要删除的用户名");
return;
}
try
{
using(SqlConnection sqlConnection = new SqlConnection(connStr))
{
// 参数化查询
string sql = "DELETE FROM SysAdmin WHERE LoginName=@name";
SqlCommand sqlCommand = new SqlCommand(sql, sqlConnection);
sqlCommand.Parameters.AddWithValue("@name", txt_LoginName.Text);
sqlConnection.Open();
int rowsAffected = sqlCommand.ExecuteNonQuery();
if(rowsAffected > 0)
MessageBox.Show("用户删除成功");
else
MessageBox.Show("未找到匹配的用户");
}
}
catch(Exception ex)
{
MessageBox.Show($"删除失败: {ex.Message}");
}
}
在实际项目中,建议使用存储过程来封装数据操作:
sql复制-- 创建添加用户的存储过程
CREATE PROCEDURE sp_AddUser
@LoginName NVARCHAR(50),
@LoginPwd NVARCHAR(100),
@RoleId INT
AS
BEGIN
INSERT INTO SysAdmin(LoginName,LoginPwd,RoleId)
VALUES(@LoginName, @LoginPwd, @RoleId)
RETURN SCOPE_IDENTITY()
END
然后在C#代码中调用:
csharp复制SqlCommand cmd = new SqlCommand("sp_AddUser", sqlConnection);
cmd.CommandType = CommandType.StoredProcedure;
// 添加参数...
明文存储密码是严重的安全隐患。应该至少使用简单的哈希算法处理:
csharp复制using System.Security.Cryptography;
private string HashPassword(string password)
{
using(var sha256 = SHA256.Create())
{
byte[] hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
return BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
}
}
// 使用
string hashedPwd = HashPassword(txt_LoginPwd.Text);
对于关键操作,应该使用事务确保数据一致性:
csharp复制using(SqlTransaction transaction = sqlConnection.BeginTransaction())
{
try
{
SqlCommand cmd1 = new SqlCommand(sql1, sqlConnection, transaction);
SqlCommand cmd2 = new SqlCommand(sql2, sqlConnection, transaction);
cmd1.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
问题现象:连接数据库时报错"无法打开登录所请求的数据库"。
解决方案:
问题现象:添加用户时报错"INSERT语句与FOREIGN KEY约束冲突"。
原因分析:尝试插入的RoleId在UserRole表中不存在。
解决方案:
csharp复制private async void btn_ADD_Click(object sender, EventArgs e)
{
try
{
using(SqlConnection sqlConnection = new SqlConnection(connStr))
{
await sqlConnection.OpenAsync();
// 异步执行命令
int rows = await sqlCommand.ExecuteNonQueryAsync();
// ...
}
}
catch(Exception ex)
{
// 错误处理
}
}
这个基础的用户管理系统还可以进一步扩展:
我在实际项目中发现,良好的异常处理和用户反馈机制能显著提升用户体验。比如当删除操作失败时,不应该只显示"删除失败",而应该根据具体原因给出更有针对性的提示,如"该用户不存在"或"该用户有关联数据,无法删除"等。