简介这是一套完整的C#房屋租赁管理系统课程设计资料包面向计算机专业学生及需要完成数据库课程设计的小白开发者帮助解决从系统设计、编码实现到报告撰写全流程的参考需求。压缩包共71个文件大小12.86MB内含C#窗体应用源码.cs与.resx/.resources窗体资源、可直接运行的.exe程序、MySQL建表脚本.sql、详细课程设计报告.doc/.docx以及ER图、数据流图等设计文档结构清晰代码与文档配套齐全。目前已有146人学习下载适合对照参考。这套资料最大价值在于无需自己从零搭建源码中涵盖房源管理、租客登记、合同签约、到期提醒等常见业务模块数据库脚本可直接导入报告附带的封皮模板与图示也能帮助快速完成课程设计文档。通过阅读源码与报告能直观掌握C#与MySQL的交互方式以及系统分层思路。1. 房屋租赁管理系统一个数据库课程设计该怎么拆把“房屋租赁管理系统”当成课程设计选题时很多人第一反应是写个 C# 窗口、连上数据库、能增删改查就交差。但最后能评上“优秀”的课程设计拉开差距的地方往往不在窗体数量而在数据关系设计房屋、租客、租约、账单这几类数据怎么组织状态怎么流转退租时怎么把账算平。这篇文章面向正在做 C# 数据库课程设计以及想用一套完整系统练手 C# 基础和数据库操作的同学。按“先设计、后编码、再避坑”的顺序把一套可运行的方案讲清楚。全程用 WinForms 加原生 ADO.NET不依赖任何框架你在 C# 入门阶段掌握的知识就够用照着做就能跑通。2. 先设计数据再写窗体房屋租赁管理系统的表结构与项目骨架数据库课程设计的评分重点一半在表设计得合不合理一半在代码能不能把表之间的关系演示清楚。所以动手写第一个窗体之前先把数据模型定下来。2.1 数据关系先于代码租客、房屋、租约三张表怎么连一套不带花哨功能的房屋租赁管理系统最少需要五张表用户表、房屋表、租客表、租约表、账单表。租约表是核心它把房屋和租客连起来账单再挂在租约下。表名关键字段状态字段作用UsersUserId, UserName, Password, Role无系统登录区分管理员和操作员HouseHouseId, HouseNo, Address, Area, MonthlyRentStatus0空置/1已租/2维修维护房源信息TenantTenantId, Name, Phone, IdCard无租客基本信息LeaseLeaseId, HouseId, TenantId, StartDate, EndDate, MonthlyRent, DepositStatus1生效中/0已终止记录一次租赁关系PaymentPaymentId, LeaseId, PayDate, Amount, PayMethod无每次缴费记录这里有个值得在报告里专门写一段的设计House 表里冗余了 Status 字段同时 Lease 表里也冗余了 MonthlyRent。为什么不实时 JOIN 算出来因为房屋状态在界面上要频繁显示每次动态计算会多一条关联查询月租金冗余到租约里是为了防止以后房价调整影响历史账单财务上这叫“快照”。字段类型也要养成习惯金额用 decimal 而不是 float身份证号用 nvarchar(18) 而不是数字类型日期用 date 或 datetime状态用 int 而不是 bit因为状态不止两种。这些细节在课程设计答辩时经常被老师拎出来问提前答得上来就是加分项。2.2 C#项目骨架WinForms 三层架构的选型与取舍很多教程一上来就让建五个项目小白直接劝退。我的建议是解决方案建两个项目就够——一个 WinForms 窗体项目负责界面一个类库项目负责数据访问。业务逻辑简单不必强行拆出 BLL否则报告写起来费劲代码也没多干净。界面层只做一件事收集用户输入、把结果显示到 DataGridView 或文本框。数据访问层只做一件事接收界面传来的参数执行 SQL返回 DataTable 或实体对象。连接字符串写到 App.config 里不硬编码在代码中这是最基础也最容易被检查的规范。这样一个简单的两层结构既满足课程设计评分标准里的“分层清晰”又不会让小白陷入过度设计。代码组织上按窗体文件分组LoginForm、MainForm、HouseForm、TenantForm、LeaseForm、PaymentForm每个窗体的数据库操作都走同一个数据访问类避免每个窗体各写一套 SqlConnection。2.3 从零建库SQL建表脚本与连接字符串的最小配置数据库我用 SQL Server这也是 C# 课程设计最常见的选择。打开 SSMS 新建数据库 RentDB然后执行下面的建表脚本CREATE TABLE Users ( UserId INT IDENTITY(1,1) PRIMARY KEY, UserName NVARCHAR(50) NOT NULL UNIQUE, Password NVARCHAR(50) NOT NULL, Role NVARCHAR(20) NOT NULL DEFAULT operator ); CREATE TABLE House ( HouseId INT IDENTITY(1,1) PRIMARY KEY, HouseNo NVARCHAR(20) NOT NULL UNIQUE, Address NVARCHAR(200) NOT NULL, RoomCount INT NOT NULL DEFAULT 1, Area DECIMAL(8,2) NOT NULL, MonthlyRent DECIMAL(10,2) NOT NULL, Status INT NOT NULL DEFAULT 0, Remark NVARCHAR(500) NULL ); CREATE TABLE Tenant ( TenantId INT IDENTITY(1,1) PRIMARY KEY, Name NVARCHAR(50) NOT NULL, Phone NVARCHAR(20) NOT NULL, IdCard NVARCHAR(18) NOT NULL, CreateTime DATETIME NOT NULL DEFAULT GETDATE() ); CREATE TABLE Lease ( LeaseId INT IDENTITY(1,1) PRIMARY KEY, HouseId INT NOT NULL REFERENCES House(HouseId), TenantId INT NOT NULL REFERENCES Tenant(TenantId), StartDate DATE NOT NULL, EndDate DATE NOT NULL, MonthlyRent DECIMAL(10,2) NOT NULL, Deposit DECIMAL(10,2) NOT NULL DEFAULT 0, Status INT NOT NULL DEFAULT 1, CreateTime DATETIME NOT NULL DEFAULT GETDATE() ); CREATE TABLE Payment ( PaymentId INT IDENTITY(1,1) PRIMARY KEY, LeaseId INT NOT NULL REFERENCES Lease(LeaseId), PayDate DATETIME NOT NULL DEFAULT GETDATE(), Amount DECIMAL(10,2) NOT NULL, PayMethod NVARCHAR(20) NOT NULL DEFAULT 现金 );注意租约表的两个外键HouseId 指向 HouseTenantId 指向 Tenant。课程设计评分标准里“表间关系”这一项凭这两行 REFERENCES 就能拿分。连接字符串写在 App.config 里connectionStrings add nameRentDB connectionStringServer127.0.0.1,1433;DatabaseRentDB;User IDsa;Password123456; providerNameSystem.Data.SqlClient / /connectionStrings用 IP 加端口而不是Server.\SQLEXPRESS是为了换机器演示时不踩实例名的坑。代码侧读取连接串并测试连通using System.Configuration; using System.Data.SqlClient; string connStr ConfigurationManager.ConnectionStrings[RentDB].ConnectionString; using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); // 抛异常说明连接串或网络有问题 }这段代码跑通等于打通了整套系统的“任督二脉”后面所有功能都是在这个连接上做文章。3. C#实战把登录、房源管理、签约退租做成能演示的功能数据库课程设计的源码部分不需要写得多高级但要把每个操作的完整链路演示清楚用户在界面上点按钮数据落到哪张表界面怎么刷新。下面按一条业务主线走登录、管房源、签租约、退租、看统计。3.1 登录与角色判断参数化查询的正确写法登录是整套系统唯一一张带条件查询的用户表操作。很多小白写成拼字符串SELECT * FROM Users WHERE UserName textBox.Text 。这样在课程设计验收时当场输入一个单引号就能让程序报错老师一眼就能看出 SQL 注入问题。用参数化查询public string Login(string userName, string password) { string sql SELECT Role FROM Users WHERE UserName name AND Password pwd; using (SqlConnection conn new SqlConnection(_connStr)) using (SqlCommand cmd new SqlCommand(sql, conn)) { cmd.Parameters.Add(name, SqlDbType.NVarChar, 50).Value userName; cmd.Parameters.Add(pwd, SqlDbType.NVarChar, 50).Value password; conn.Open(); object role cmd.ExecuteScalar(); return role?.ToString(); } }ExecuteScalar 返回第一行第一列正好拿角色。参数用cmd.Parameters.Add指定类型和长度不要图省事全用 AddWithValue——AddWithValue 会按 C# 侧类型推断 SQL 参数类型遇到 nvarchar 和 varchar 混用的情况索引可能失效课程设计里虽然不是性能场景但养成的习惯是好的。登录成功后把角色存到全局变量管理员看到“房屋管理、租约管理、系统设置”等所有菜单操作员只能看到业务功能。这个控制逻辑写在主窗体的菜单加载事件里按 Role 判断 Visible 即可。3.2 房源信息增删改查DataGridView绑定与状态管理房源管理是整套系统里最标准的增删改查页面。查询用 SqlDataAdapter 直接填 DataTable这样绑定 DataGridView 时不需要手动一行行构造public DataTable GetAllHouses() { string sql SELECT HouseId, HouseNo, Address, RoomCount, Area, MonthlyRent, CASE Status WHEN 0 THEN N空置 WHEN 1 THEN N已租 ELSE N维修 END AS StatusText FROM House ORDER BY HouseNo; DataTable table new DataTable(); using (SqlConnection conn new SqlConnection(_connStr)) using (SqlDataAdapter adapter new SqlDataAdapter(sql, conn)) { adapter.Fill(table); return table; } }CASE 直接在 SQL 里把状态数字转成中文界面侧就不用再写一层翻译逻辑。新增房屋的插入语句public bool AddHouse(HouseInfo house) { string sql INSERT INTO House (HouseNo, Address, RoomCount, Area, MonthlyRent, Status, Remark) VALUES (no, address, room, area, rent, status, remark); using (SqlConnection conn new SqlConnection(_connStr)) using (SqlCommand cmd new SqlCommand(sql, conn)) { cmd.Parameters.Add(no, SqlDbType.NVarChar, 20).Value house.HouseNo; cmd.Parameters.Add(address, SqlDbType.NVarChar, 200).Value house.Address; cmd.Parameters.Add(room, SqlDbType.Int).Value house.RoomCount; cmd.Parameters.Add(area, SqlDbType.Decimal).Value house.Area; cmd.Parameters.Add(rent, SqlDbType.Decimal).Value house.MonthlyRent; cmd.Parameters.Add(status, SqlDbType.Int).Value 0; // 新增房源默认空置 cmd.Parameters.Add(remark, SqlDbType.NVarChar, 500).Value house.Remark ?? ; conn.Open(); return cmd.ExecuteNonQuery() 0; } }注意house.Remark ?? Nullable 字段不处理会变成空字符串插入失败这是 C# 里最容易踩的类型边界。执行成功后重新调用 GetAllHouses 并重新绑定 DataSource完成一次“增”的闭环。删除房源时要小心这就是第 4 章要重点讲的外键坑。现在先记住一个原则删除不是 UPDATE 一下 IsDeleted 字段就是万能的关键看你有没有历史租约引用它。3.3 签约与退租SqlTransaction保证数据一致签约这个动作业务上涉及两张表往 Lease 表插入一条租约记录同时把 House 表的 Status 改成 1已租。如果不用事务插入租约成功但更新房屋状态失败系统里就出现一套“已出租的房屋还能再租给别人”的脏数据。public bool SignLease(LeaseInfo lease, int houseId, int tenantId) { string insertLease INSERT INTO Lease (HouseId, TenantId, StartDate, EndDate, MonthlyRent, Deposit, Status) VALUES (houseId, tenantId, start, end, rent, deposit, 1); string updateHouse UPDATE House SET Status 1 WHERE HouseId houseId AND Status 0; using (SqlConnection conn new SqlConnection(_connStr)) { conn.Open(); SqlTransaction tran conn.BeginTransaction(); try { SqlCommand cmd1 new SqlCommand(insertLease, conn, tran); cmd1.Parameters.Add(houseId, SqlDbType.Int).Value houseId; cmd1.Parameters.Add(tenantId, SqlDbType.Int).Value tenantId; cmd1.Parameters.Add(start, SqlDbType.Date).Value lease.StartDate; cmd1.Parameters.Add(end, SqlDbType.Date).Value lease.EndDate; cmd1.Parameters.Add(rent, SqlDbType.Decimal).Value lease.MonthlyRent; cmd1.Parameters.Add(deposit, SqlDbType.Decimal).Value lease.Deposit; cmd1.ExecuteNonQuery(); SqlCommand cmd2 new SqlCommand(updateHouse, conn, tran); cmd2.Parameters.Add(houseId, SqlDbType.Int).Value houseId; int affected cmd2.ExecuteNonQuery(); if (affected 0) { throw new InvalidOperationException(房屋状态不是空置无法签约); } tran.Commit(); return true; } catch { tran.Rollback(); return false; } } }这段代码是整套源码里最容易被老师截图放进报告的。UPDATE 语句里的AND Status 0是一个乐观锁思想如果两个人同时签同一套房子第二个人执行更新时 affected 为 0直接被拦下。退租是反向操作业务逻辑更复杂一些把 Lease.Status 改成 0把 House.Status 改成 0同时还要根据已交租金和实际租期算一笔结算账单写入 Payment。这三步同样放在一个事务里。很多小白退租只改一个状态导致房子显示空置但租约还挂着演示到这一步必然露馅。3.4 房租统计与出租率用SQL完成课程设计的加分查询课程设计报告里必须有“统计报表”这一章老师也默认会问“这系统能统计什么”。不需要做复杂的图表控件两条 SQL 就能撑起这个模块。按月汇总房租收入SELECT DATEPART(YEAR, PayDate) AS 年份, DATEPART(MONTH, PayDate) AS 月份, SUM(Amount) AS 实收金额 FROM Payment GROUP BY DATEPART(YEAR, PayDate), DATEPART(MONTH, PayDate) ORDER BY 年份, 月份;按当前房源算出租率SELECT CAST(SUM(CASE WHEN Status 1 THEN 1 ELSE 0 END) AS DECIMAL(5,2)) / COUNT(*) AS 出租率 FROM House;把这两个查询结果塞进 DataTable绑定到 DataGridView再提供一个“导出 CSV”按钮报表模块就齐了。导出 CSV 时用 UTF-8 with BOM 编码Excel 打开中文才不会乱码var sb new StringBuilder(); foreach (DataColumn col in table.Columns) { sb.Append(col.ColumnName).Append(,); } sb.Length--; // 去掉最后一个多余的逗号 sb.AppendLine(); foreach (DataRow row in table.Rows) { foreach (DataColumn col in table.Columns) { sb.Append(row[col.ColumnName]).Append(,); } sb.Length--; sb.AppendLine(); } System.IO.File.WriteAllText(房租统计.csv, sb.ToString(), Encoding.UTF8);这个 CSV 导出方案不需要装 Office 组件在机房验收时不会因为机器没装 Excel 而翻车。4. 常见问题与避坑5个让小白翻车的数据库细节课程设计翻车很少翻在业务逻辑上多半是栽在环境、编码和约束这些小细节上。下面这 5 条几乎每年都有人踩按“现象 → 原因 → 解决”记录演示前逐条对照检查。4.1 连接字符串换机器就连不上数据库现象在自己笔记本上运行正常到教室电脑一打开就抛 SqlException提示“在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误”。原因连接字符串写死了本机的 SQL Server 实例名比如Server.\SQLEXPRESS换一台机器实例名不对或者教室机器的 SQL Server 服务没启动或者用了 Windows 身份验证而当前登录用户没有数据库权限。解决统一改成 SQL Server 身份验证写成Server127.0.0.1,1433;DatabaseRentDB;User IDsa;Password123456;并放到 App.config。演示前一天到教室先跑一次conn.Open()测试代码别等老师坐在旁边了才发现连不上。提交源码时把 App.config 一起交并在报告里写清楚“数据库连接串在配置文件中修改”。4.2 中文存进去变成问号现象窗体里正常输入“张伟”保存到数据库后变成“张??”或者“???”界面一刷新显示乱码。原因列类型用了 varchar。SQL Server 的 varchar 按非 Unicode 存储中文字符在数据库代码页不支持时直接丢失。MySQL 场景下则是连接字符串没指定 utf8mb4。解决SQL Server 建表一律用 nvarchar插入时参数类型用 SqlDbType.NVarChar。如果你的建表脚本里已经有INSERT INTO … VALUES (N张伟)这种带 N 前缀的写法说明你已经在往正确的方向靠了。MySQL 用户记得在连接字符串里加CharSetutf8mb4;同时表字符集也要对齐。检查方法很简单在 SSMS 里直接查询列的类型看到 varchar 就改。4.3 删除数据提示外键约束冲突现象删一条房屋记录抛“DELETE 语句与 REFERENCE 约束冲突”看半天不知道哪里被引用了。原因Lease 表里有外键指向 House这恰恰说明你的外键建对了。数据库不允许删有子表引用的父表这是约束在起作用。解决用软删除。给 House 表加一个 IsDeleted 字段0 正常 / 1 已删除删除操作改为 UPDATEUPDATE House SET IsDeleted 1 WHERE HouseId houseId;所有列表查询默认加WHERE IsDeleted 0。这样历史租约的 HouseId 还能继续关联报告里也能写“软删除保留了历史数据便于事后审计”比硬删高级一个档次。如果实在需要物理删除就按“先删子表、再删父表”的顺序处理但租约关联的缴费记录会一起丢不推荐。4.4 DataGridView列标题变成英文字段名现象给 DataGridView 设了 DataSource列头显示 HouseId、HouseNo、Area 这种英文列顺序也跟你想的不一样。原因DataGridView 的 AutoGenerateColumns 默认为 true它会自动为数据源里的每一列生成一列字段名直接当表头。想自定义列标题就得关掉它。解决在设计器里把 AutoGenerateColumns 设为 false然后手动配置列dataGridView1.AutoGenerateColumns false; dataGridView1.Columns.Clear(); dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName HouseNo, HeaderText 房号, Width 100 }); dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName Address, HeaderText 地址, Width 200 });DataPropertyName 对应 SQL 查询返回的字段名HeaderText 是界面显示的标题。推荐把 SQL 里的字段名改成无下划线的驼峰写法免得绑定时字段名对不上。4.5 按日期范围查询漏数据现象选“2024-01-01 到 2024-01-31”查出来的账单少了 1 月 31 日晚上交的那几条。退租截止日期也总是差一天。原因DateTime 比较的边界问题。很多人拼 SQL 时把 C# 的 DateTime 转成2024-01-31字符串数据库把它解析成 2024-01-31 00:00:00那么当天 23:59 交的费就被排除在外。用 BETWEEN 也一样BETWEEN 是闭区间但字符串转出来的起点是零点。解决传参数不要转字符串直接传 DateTime 对象查某一天用左闭右开区间DateTime start dtpBegin.Value.Date; // 当天 0 点 DateTime end start.AddDays(1); // 次日 0 点 cmd.Parameters.Add(start, SqlDbType.DateTime).Value start; cmd.Parameters.Add(end, SqlDbType.DateTime).Value end;SQL 侧写成PayDate start AND PayDate end。退租截止也是同理StartDate 存当天零点EndDate 逻辑上就是下一周期起点不要让客户“多住一晚”。5. 验收与答辩演示路径、报告素材和必答问题源码写完只是第一步能不能被评上优秀课程设计还要看演示和报告怎么组织。我最推荐的演示路径是一条完整业务链登录 → 添加房源 → 新增租客 → 签约 → 缴费 → 退租 → 查看统计报表。每个步骤说清楚“刚才那个操作改了哪张表哪个字段”比挨个窗体演示更有说服力。演示数据提前准备 5 套左右用真实感强的地址和名字比如“阳光花园 3 栋 502”“月租金 1800”。空数据库现场录入既慢又容易手误老师看着也乏味。签约环节务必现场操作一次让老师看到 Lease 表多了一条记录、House 表状态从“空置”变“已租”这比任何 PPT 截图都直观。报告素材方面ER 图用 draw.io 画清楚三张核心表和它们的关系数据字典列出字段类型和说明核心代码只贴登录参数化查询、事务签约、统计 SQL 这三段。整份源码包按“sln SQL脚本 数据库备份 报告文档”四部分整理老师拿到手能直接跑这个习惯本身就会加分。答辩被问频率最高的问题就几个为什么用事务、为什么冗余状态字段、外键有什么用、连接为什么用 using。提前把 2.1 和 3.3 里的思路用自己的话复述一遍基本都能接住。我当年做这套项目的时候偷懒先写了界面再补表结构结果中途改了三次数据库脚本界面跟着返工浪费了整整一个周末。后来养成的习惯是任何和数据库打交道的课程设计先画 ER 图、定字段类型、列外键关系再碰界面代码。这套顺序看着慢实际是最快的路希望帮到你。本文还有配套的精品资源点击获取