如何在Windows窗体中记录Access数据库字段更新者及时间并展示
实现操作日志功能的完整方案
我来帮你一步步搞定这个操作日志功能,从数据库表创建到代码修改再到UI展示,全部安排明白:
1. 先在Access数据库中创建操作日志表
打开你的Database21.accdb,新建一张名为OperationLogs的表,字段设置如下:
LogID:自动编号(主键,自动生成唯一标识)Operator:文本类型(存储操作人用户名)OperationTime:日期/时间类型(精准记录操作发生的时间)OperationType:文本类型(比如"插入"、"更新"、"删除",明确操作类型)Description:备注类型(详细描述操作内容,比如"插入了记录:姓名=张三")
嫌手动建表麻烦?直接在Access的SQL视图执行这段语句就能快速创建:
CREATE TABLE OperationLogs ( LogID AUTOINCREMENT PRIMARY KEY, Operator TEXT(50), OperationTime DATETIME, OperationType TEXT(20), Description MEMO );
2. 修改Form1代码,添加日志记录逻辑
我先给你封装一个通用的写日志方法,这样每个操作里不用重复写日志逻辑;另外顺便把你原来的SQL字符串拼接改成了参数化查询——这很重要,能避免SQL注入风险,还能防止特殊字符导致的语法错误:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.OleDb; using System.Security.Principal; namespace WindowsFormsApplication1 { public partial class Form1 : Form { OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\saurabh.ad.sharma\Documents\test2\Database21.accdb"); int count = 0; public Form1() { InitializeComponent(); // 初始化时隐藏日志表格,只显示主数据表格 dataGridViewLogs.Visible = false; } // 封装通用的写日志方法 private void WriteOperationLog(string operationType, string description) { try { // 获取当前操作人(这里用系统用户名,如果你有登录模块可以替换成登录用户) string operatorName = WindowsIdentity.GetCurrent().Name; string insertLogSql = @"INSERT INTO OperationLogs (Operator, OperationTime, OperationType, Description) VALUES (@Operator, @OperationTime, @OperationType, @Description)"; con.Open(); OleDbCommand cmd = new OleDbCommand(insertLogSql, con); cmd.Parameters.AddWithValue("@Operator", operatorName); cmd.Parameters.AddWithValue("@OperationTime", DateTime.Now); cmd.Parameters.AddWithValue("@OperationType", operationType); cmd.Parameters.AddWithValue("@Description", description); cmd.ExecuteNonQuery(); } catch (Exception ex) { MessageBox.Show($"日志写入失败:{ex.Message}"); } finally { if (con.State == ConnectionState.Open) con.Close(); } } private void button1_Click(object sender, EventArgs e) { try { string insertSql = "INSERT INTO table1 VALUES (@Name, @Value)"; con.Open(); OleDbCommand cmd = new OleDbCommand(insertSql, con); cmd.Parameters.AddWithValue("@Name", textBox1.Text); cmd.Parameters.AddWithValue("@Value", textBox2.Text); cmd.ExecuteNonQuery(); // 写入插入操作日志 WriteOperationLog("插入", $"插入记录:姓名={textBox1.Text},值={textBox2.Text}"); textBox1.Text = ""; textBox2.Text = ""; MessageBox.Show("record inserted successfully"); } catch (Exception ex) { MessageBox.Show($"插入失败:{ex.Message}"); } finally { if (con.State == ConnectionState.Open) con.Close(); } } private void button4_Click(object sender, EventArgs e) { try { con.Open(); OleDbCommand cmd = con.CreateCommand(); cmd.CommandType = CommandType.Text; cmd.CommandText = "select * from table1"; DataTable dt = new DataTable(); OleDbDataAdapter da = new OleDbDataAdapter(cmd); da.Fill(dt); dataGridView1.DataSource = dt; // 切换显示主数据表格,隐藏日志表格 dataGridView1.Visible = true; dataGridViewLogs.Visible = false; } catch (Exception ex) { MessageBox.Show($"加载数据失败:{ex.Message}"); } finally { if (con.State == ConnectionState.Open) con.Close(); } } private void button2_Click(object sender, EventArgs e) { try { string deleteSql = "DELETE FROM table1 WHERE name=@Name"; con.Open(); OleDbCommand cmd = new OleDbCommand(deleteSql, con); cmd.Parameters.AddWithValue("@Name", textBox1.Text); int rowsAffected = cmd.ExecuteNonQuery(); if (rowsAffected > 0) { // 写入删除操作日志 WriteOperationLog("删除", $"删除记录:姓名={textBox1.Text}"); MessageBox.Show("record deleted successfully"); } else { MessageBox.Show("未找到要删除的记录"); } } catch (Exception ex) { MessageBox.Show($"删除失败:{ex.Message}"); } finally { if (con.State == ConnectionState.Open) con.Close(); } } private void button3_Click(object sender, EventArgs e) { try { string updateSql = "UPDATE table1 SET name=@NewName WHERE name=@OldName"; con.Open(); OleDbCommand cmd = new OleDbCommand(updateSql, con); cmd.Parameters.AddWithValue("@NewName", textBox2.Text); cmd.Parameters.AddWithValue("@OldName", textBox1.Text); int rowsAffected = cmd.ExecuteNonQuery(); if (rowsAffected > 0) { // 写入更新操作日志 WriteOperationLog("更新", $"更新记录:原姓名={textBox1.Text},新姓名={textBox2.Text}"); MessageBox.Show("record updated successfully"); } else { MessageBox.Show("未找到要更新的记录"); } } catch (Exception ex) { MessageBox.Show($"更新失败:{ex.Message}"); } finally { if (con.State == ConnectionState.Open) con.Close(); } } private void button5_Click(object sender, EventArgs e) { count = 0; try { con.Open(); OleDbCommand cmd = con.CreateCommand(); cmd.CommandType = CommandType.Text; cmd.CommandText = "select * from table1 where name=@Name"; cmd.Parameters.AddWithValue("@Name", textBox1.Text); DataTable dt = new DataTable(); OleDbDataAdapter da = new OleDbDataAdapter(cmd); da.Fill(dt); count = dt.Rows.Count; dataGridView1.DataSource = dt; // 切换显示主数据表格,隐藏日志表格 dataGridView1.Visible = true; dataGridViewLogs.Visible = false; if (count == 0) { MessageBox.Show("record not found"); } } catch (Exception ex) { MessageBox.Show($"查询失败:{ex.Message}"); } finally { if (con.State == ConnectionState.Open) con.Close(); } } // 新增:查看日志按钮的点击事件(需要你在窗体上添加名为btnViewLogs的按钮) private void btnViewLogs_Click(object sender, EventArgs e) { try { con.Open(); OleDbCommand cmd = con.CreateCommand(); cmd.CommandType = CommandType.Text; // 按时间倒序显示,最新的日志排在最前面 cmd.CommandText = "SELECT * FROM OperationLogs ORDER BY OperationTime DESC"; DataTable dt = new DataTable(); OleDbDataAdapter da = new OleDbDataAdapter(cmd); da.Fill(dt); dataGridViewLogs.DataSource = dt; // 切换显示日志表格,隐藏主数据表格 dataGridView1.Visible = false; dataGridViewLogs.Visible = true; } catch (Exception ex) { MessageBox.Show($"加载日志失败:{ex.Message}"); } finally { if (con.State == ConnectionState.Open) con.Close(); } } } }
3. 在窗体上添加查看日志的UI元素
打开Form1的设计器,做两个简单的操作:
- 添加一个新的
Button控件,命名为btnViewLogs,把Text属性改成"查看操作日志" - 添加一个新的
DataGridView控件,命名为dataGridViewLogs,调整它的大小和位置和dataGridView1完全一致,这样切换显示时看起来是在同一区域展示内容
4. 额外小提示
- 如果只需要显示用户名而不是"域名\用户名",可以把
WindowsIdentity.GetCurrent().Name换成Environment.UserName - 日志的描述信息可以根据你的需求扩展,比如记录更多字段的变更内容
- 参数化查询的改动一定要保留,这是避免安全问题和语法错误的关键
内容的提问来源于stack exchange,提问作者saurabh255
相关产品推荐
相关产品推荐

