简介:这是一份面向C#初学者与中小型企业管理软件开发者的台账记录系统设计源码,可用于学习WinForms桌面应用的分层架构与业务实现,也可作为企业台账管理工具的二次开发基础。压缩包共67个文件、约384KB,以41个C#源代码文件为核心,配合11个resx资源文件、3个csproj项目文件、2个sln解决方案文件,以及png图标、settings配置、config配置和db3数据库文件,覆盖界面、业务逻辑与数据持久化各层。目录中可见AccountLog、CheckPay、ConsoleApplication1等模块,以及Form系列窗体、UserCtrl自定义控件、sqlUtil数据库工具类与Services服务层,结构清晰,便于按模块阅读。目前已有351人学习下载。读者可从中掌握窗体设计、数据增删改查、数据库连接配置与项目组织方式,并借鉴工厂、单例等设计模式的落地写法,快速搭建或扩展自己的台账管理程序。
1. 台账记录系统源码拆包:C# 桌面端 CRUD 到底能省多少事
很多做内部管理软件的同行都有过这种经历:车间要记设备点检、仓库要记出入库、行政要记资产领用,需求方一句“就做个简单的台账”,真动手时才发现字段要自定义、查询要组合、导出要 Excel、权限还分三级。从零搭一套 C# 台账记录系统,光是数据访问层和界面绑定就能耗掉一周。这份基于 C# 语言的台账记录系统设计源码,解决的就是这类“看着简单、写起来琐碎”的场景。它把台账的增删改查、条件筛选、列表分页、数据导出这几块骨架搭好了,适合刚接触 C# 上位机或管理类桌面项目的开发者拿来改字段、换业务逻辑,也适合需要快速交付内部工具的老手做二次开发底座。源码结构不复杂,但该有的分层和异常处理都在,能直接跑起来看效果。
2. 环境准备与工程结构:把源码跑起来的第一道坎
2.1 运行环境与依赖确认
拿到一份 C# 源码,第一件事不是急着打开解决方案,而是确认目标框架和依赖项。这份台账记录系统常见做法是基于 .NET Framework 4.7.2 或 .NET 6 的 WinForms 工程,数据库多采用 SQL Server 或 Access。如果你机器上只有 .NET 8 SDK,直接双击 .sln 可能会提示框架不兼容。我一般会先看项目文件里的<TargetFramework>节点,再决定装哪个版本的运行时。
需要提前装好的东西:
- Visual Studio 2022(社区版够用),安装时勾选“.NET 桌面开发”工作负载
- SQL Server Express 或 LocalDB,如果源码用的是 Access 则需装 Microsoft ACE OLEDB 驱动
- 对应的 .NET 运行时,版本以
.csproj里写的为准
提示:Access 数据库在 64 位系统上跑,必须用 64 位的 ACE 驱动,否则会报“未在本地计算机上注册 Microsoft.ACE.OLEDB.12.0”这个经典错误。
2.2 工程目录与分层逻辑
解压后典型的目录结构是这样的,不同版本可能略有出入,但分层思路一致:
LedgerSystem/ ├── LedgerSystem.sln ├── LedgerSystem/ │ ├── App.config │ ├── Program.cs │ ├── Forms/ │ │ ├── MainForm.cs │ │ ├── LedgerEditForm.cs │ │ └── LoginForm.cs │ ├── DAL/ │ │ ├── SqlHelper.cs │ │ └── LedgerRepository.cs │ ├── Models/ │ │ └── LedgerItem.cs │ └── Utils/ │ └── ExcelExporter.csForms放界面,DAL放数据访问,Models放实体类,Utils放导出等工具方法。这种分法不算精致,但对台账类项目足够。你要改业务,重点动Models和LedgerRepository;要改界面,动Forms下的窗体文件。
2.3 数据库连接配置与首次运行
连接字符串一般写在App.config里,改完直接生效,不用重新编译:
<configuration> <connectionStrings> <!-- 改成你自己的服务器地址和库名 --> <add name="LedgerDb" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=LedgerDB;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>Data Source填服务器实例名,Initial Catalog填数据库名,Integrated Security=True表示用 Windows 身份验证,省去账号密码。如果换成 SQL 账号登录,改成User Id=sa;Password=你的密码。
首次运行前,源码包里通常带一个.sql建表脚本,在 SSMS 里执行一遍建库建表。如果没带脚本,就照着Models/LedgerItem.cs里的属性手动建表,字段名和类型对齐即可。跑起来后先点“新增”录一条测试数据,能存进去、列表能刷出来,说明环境通了。
3. 核心功能实现:增删改查与数据绑定的关键代码
3.1 实体类与数据访问层
台账系统的核心是一张主表加若干字典表。实体类定义字段,数据访问层负责拼 SQL。先看实体类:
public class LedgerItem { public int Id { get; set; } // 主键,自增 public string ItemName { get; set; } // 台账名称 public string Category { get; set; } // 分类 public decimal Amount { get; set; } // 数量或金额 public DateTime RecordDate { get; set; } // 记录日期 public string Operator { get; set; } // 经办人 public string Remark { get; set; } // 备注 }字段类型要和数据库列类型对应,decimal对应decimal(18,2),DateTime对应datetime。类型不匹配是查询报错的高发区,尤其是金额字段用float会丢精度,台账场景必须用decimal。
数据访问层用参数化查询,别拼字符串:
public List<LedgerItem> Query(string keyword, DateTime? start, DateTime? end) { var list = new List<LedgerItem>(); var sql = "SELECT * FROM Ledger WHERE 1=1"; var pars = new List<SqlParameter>(); if (!string.IsNullOrEmpty(keyword)) { sql += " AND ItemName LIKE @kw"; pars.Add(new SqlParameter("@kw", "%" + keyword + "%")); } if (start.HasValue) { sql += " AND RecordDate >= @start"; pars.Add(new SqlParameter("@start", start.Value)); } if (end.HasValue) { sql += " AND RecordDate <= @end"; pars.Add(new SqlParameter("@end", end.Value)); } using (var conn = new SqlConnection(connStr)) using (var cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddRange(pars.ToArray()); conn.Open(); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { list.Add(new LedgerItem { Id = (int)reader["Id"], ItemName = reader["ItemName"].ToString(), Amount = Convert.ToDecimal(reader["Amount"]), RecordDate = Convert.ToDateTime(reader["RecordDate"]) }); } } } return list; }1=1是个常用技巧,后面所有条件都用AND拼接,不用判断第一个条件。LIKE查询的%要加在参数值里,不能写在 SQL 里,否则参数化就白做了。using保证连接和命令对象用完即释放,台账系统并发不高,但连接泄漏照样会把连接池耗干。
3.2 界面数据绑定与分页
WinForms 里把List<LedgerItem>直接赋给DataGridView.DataSource就能显示,但数据量大时全量加载会卡。常见做法是分页查询,每页 20 到 50 条:
private void LoadPage(int pageIndex, int pageSize) { var sql = @"SELECT * FROM Ledger ORDER BY Id OFFSET @offset ROWS FETCH NEXT @size ROWS ONLY"; // OFFSET 分页需要 SQL Server 2012 及以上版本 int offset = (pageIndex - 1) * pageSize; // ... 执行查询并绑定 dgvLedger.DataSource = pageList; lblPage.Text = $"第 {pageIndex} 页"; }OFFSET ... FETCH NEXT是 SQL Server 2012 之后的标准分页写法,比ROW_NUMBER()简洁。如果源码用的是 Access,分页得用TOP加子查询,写法不同,改的时候注意数据库类型。
编辑和删除按主键操作,删除前弹确认框,这是台账类软件的基本素养。编辑窗体打开时把当前行数据传进去,保存时用UPDATE语句按Id更新,别用INSERT重复插入。
3.3 数据导出到 Excel
台账做完,用户十有八九要导出。源码里一般用 NPOI 或 EPPlus 库,不依赖 Office 安装。以 NPOI 为例:
public void ExportToExcel(List<LedgerItem> data, string filePath) { IWorkbook workbook = new XSSFWorkbook(); // .xlsx 格式 ISheet sheet = workbook.CreateSheet("台账记录"); // 表头 IRow header = sheet.CreateRow(0); header.CreateCell(0).SetCellValue("编号"); header.CreateCell(1).SetCellValue("名称"); header.CreateCell(2).SetCellValue("金额"); header.CreateCell(3).SetCellValue("日期"); // 数据行 for (int i = 0; i < data.Count; i++) { IRow row = sheet.CreateRow(i + 1); row.CreateCell(0).SetCellValue(data[i].Id); row.CreateCell(1).SetCellValue(data[i].ItemName); row.CreateCell(2).SetCellValue((double)data[i].Amount); row.CreateCell(3).SetCellValue(data[i].RecordDate.ToString("yyyy-MM-dd")); } using (var fs = new FileStream(filePath, FileMode.Create)) { workbook.Write(fs); } }XSSFWorkbook对应.xlsx,HSSFWorkbook对应.xls。金额转double是为了写入单元格,但源数据保持decimal不动。日期格式化用yyyy-MM-dd,避免导出后变成一串数字。导出路径让用户自己选,用SaveFileDialog,别写死在代码里。
4. 避坑与排查:台账系统开发中最容易翻车的几个点
4.1 中文乱码与编码问题
现象:从 Excel 导入或导出后,中文变成问号或乱码。原因通常是文件流没指定编码,或者数据库排序规则不是中文。解决:读写文件时显式用Encoding.UTF8,数据库建库时排序规则选Chinese_PRC_CI_AS。Access 数据库还要注意字段长度,短文本默认 255,超了会截断。
4.2 并发编辑导致数据覆盖
现象:两个人同时打开同一条记录编辑,后保存的把先保存的覆盖了。原因:没有做乐观并发控制。解决:表里加一个RowVersion或UpdateTime字段,更新时带上WHERE UpdateTime = @oldTime,受影响行数为 0 就提示“数据已被他人修改,请刷新”。台账系统用户不多,但这个坑一旦踩了,数据对不上很难查。
4.3 日期范围查询漏掉当天数据
现象:查 3 月 1 日到 3 月 31 日,31 号当天的记录查不出来。原因:RecordDate存的是datetime,带时分秒,<= '2024-03-31'实际是<= '2024-03-31 00:00:00'。解决:结束日期加一天,用< @end.AddDays(1),或者把字段改成date类型只存日期。这个坑几乎每个做查询的人都会踩一次。
4.4 连接字符串明文暴露
现象:源码发给别人或上传后,数据库账号密码直接写在App.config里。原因:图省事。解决:至少用aspnet_regiis加密配置节,或者把敏感信息放环境变量。内部工具也别裸奔,尤其是带sa账号的。
4.5 DataGridView 绑定后修改不生效
现象:改了DataSource里的对象属性,界面不刷新。原因:List<T>不实现INotifyPropertyChanged,绑定是一次性的。解决:改用BindingList<T>,或者改完重新赋值DataSource。台账编辑场景建议用BindingList,省去手动刷新的麻烦。
5. 二次开发与验证:把通用台账改成你的业务台账
拿到这份源码,最终目的是改成自己场景能用的东西。改之前先做一次完整验证:新增一条记录、修改它、按条件查出来、导出 Excel、再删掉。五步走通,说明骨架没问题,可以动刀了。
二次开发的核心是换实体和换查询条件。比如你要做设备点检台账,把LedgerItem里的Category换成DeviceCode,Amount换成CheckResult,然后在Query方法里加按设备编号筛选。界面上的DataGridView列名在 Designer 里改,或者运行时用dgvLedger.Columns["Category"].HeaderText = "设备编号"动态改。
一个实用技巧是加“字典表”支持。台账里的分类、状态这类字段,别硬编码在代码里,建一张Dict表存DictType和DictValue,界面上用ComboBox绑定。这样以后加分类不用改代码,改数据就行。我一般会在Models下加一个DictItem类,在DAL里加GetDictByType(string type)方法,窗体加载时调一次填充下拉框。
验证改动是否成功,别只看界面。打开 SSMS 直接查库,确认写入的数据和界面显示一致。导出功能重点测特殊字符,比如名称里带逗号、引号,看 Excel 里是否正常。日期字段测跨月跨年,分页测最后一页数据量不足时会不会报错。
从那以后我每次拿到这类管理系统的源码,都强制先跑一遍“增删改查导”五步验证,再动任何业务代码。骨架没通就改业务,等于在沙地上盖楼。希望这份拆解能帮你少走点弯路,把台账系统快速落地成能交差的东西。
本文还有配套的精品资源,点击获取