news 2026/9/28 1:54:27

C#医药销售管理系统源码解析:SQL Server 2000附加数据库与WinForms实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#医药销售管理系统源码解析:SQL Server 2000附加数据库与WinForms实战

简介:这是一套面向高校计算机专业学生与C#初学者、WinForm开发者的医药销售管理系统完整源码工程,可用于课程设计、毕业设计或自学练手,帮助理解数据库驱动的桌面业务系统如何落地。压缩包共290个文件,约2.49MB,以78个cs源码文件、72个ico图标、72个resx资源文件及25个resources资源为主,另含sln解决方案、csproj项目文件、sql建库脚本与mdf、ldf数据库文件,结构完整可直接编译运行。数据库需采用SQL Server 2000,将database文件夹中的MSMS_Data、MSMS_Log附加即可,也可通过MSMS.sql导入建库;系统管理员账号与密码均为8,其余数据可进入系统或直接查询数据库获取。源码中可见药品查询、药品信息管理等模块,适合对照学习窗体布局、数据绑定与增删改查实现思路。目前已有141人学习下载,可作为医药销售类管理系统的参考模板。

1. 从一份 C# 医药销售管理系统源码包说起:SQL Server 2000 附加数据库就能跑

如果你手头正好有一份基于 C# 的医药销售管理系统源码包,解压后看到MSMS.csproj、YaoPinChaXun.cs、YaoPinXinXiGuanLi.cs这些文件,第一反应大概率是「这玩意儿还能不能跑起来」。这份资源的核心价值在于它是一套完整的 WinForms 桌面应用,覆盖了药品查询、药品信息管理、销售记录等医药流通场景的基础业务,数据库层用的是 SQL Server 2000,源码和数据库文件都打包在一起。它适合两类人:一类是刚接触 C# 和数据库增删改查、想找一个真实业务系统练手的开发者;另一类是手里有老系统维护需求、需要参考同类实现思路的从业者。需要提前说清楚的是,SQL Server 2000 是这套系统的硬性依赖,数据库文件MSMS_Data和MSMS_Log已经放在database文件夹里,直接附加即可,也可以用MSMS.sql脚本导入的方式创建。系统管理员账号是 8,密码也是 8,这个默认凭据在第一次登录时就会用到。整套代码没有花哨的架构,就是典型的 WinForms + ADO.NET 直连数据库,正因为简单,反而适合拿来拆解一个业务系统从建库到界面的完整链路。

2. 环境搭建与数据库附加:SQL Server 2000 的安装边界和替代方案

2.1 为什么这套系统锁死了 SQL Server 2000

先讲清楚一个现实问题:SQL Server 2000 在 Windows 10/11 上直接安装的成功率很低,常见做法是放在 Windows 7 虚拟机或者 Windows Server 2003/2008 环境里跑。这套系统之所以锁死 2000,是因为它的数据库文件格式是 MDF/LDF 的早期版本,高版本 SQL Server 虽然支持附加,但附加后会自动升级数据库兼容级别,一旦升级就回不去了。如果你只是想把系统跑起来看看效果,用 SQL Server 2008 R2 或 2012 附加也能打开,但要注意附加时不要勾选「升级」相关的选项,否则原文件会被改写。更稳妥的做法是先把database文件夹整体复制一份备份,再在副本上操作。

另一个边界是连接字符串。这套源码里的连接配置大概率写的是Data Source=.;Initial Catalog=MSMS;User ID=sa;Password=...这种形式,如果你本机的 SQL Server 实例名不是默认实例,或者用了命名实例,就需要改App.config或者代码里硬编码的连接串。常见做法是在App.config里加一个connectionStrings节点,把连接串抽出来,这样换环境时只改一处。

2.2 附加数据库的两种路径:图形界面和 T-SQL

第一种路径是图形界面附加。打开 SQL Server 企业管理器(2000)或 SSMS(高版本),右键「数据库」→「附加」,找到database文件夹下的MSMS_Data.MDF,确认日志文件MSMS_Log.LDF路径正确,点确定。如果提示「附加失败,日志文件找不到」,说明 MDF 和 LDF 不在同一目录或者文件名被改过,需要手动指定 LDF 路径。

第二种路径是用MSMS.sql脚本导入。这种方式更适合没有 MDF 文件或者想重建库的场景。操作步骤是:先新建一个空数据库,名字叫MSMS,然后在查询窗口里打开MSMS.sql,执行。注意脚本里可能包含CREATE DATABASE语句,如果目标库已经存在会报错,常见做法是把脚本开头的建库语句注释掉,只保留建表和插入数据的部分。

-- 如果 MSMS.sql 里包含建库语句,先检查这一段 -- CREATE DATABASE MSMS -- ON PRIMARY (NAME = N'MSMS_Data', FILENAME = N'D:\database\MSMS_Data.MDF') -- LOG ON (NAME = N'MSMS_Log', FILENAME = N'D:\database\MSMS_Log.LDF') -- 如果目标库已存在,把上面几行注释掉,直接从 USE MSMS 开始执行 USE MSMS GO -- 建表语句示例:药品信息表 CREATE TABLE YaoPinXinXi ( YaoPinID INT IDENTITY(1,1) PRIMARY KEY, YaoPinMingCheng NVARCHAR(100) NOT NULL, ShengChanChangJia NVARCHAR(200), PiZhunWenHao NVARCHAR(50), DanJia DECIMAL(10,2), KuCunLiang INT DEFAULT 0 ) GO

这段 SQL 的逻辑是先切到MSMS库,然后建一张药品信息表。IDENTITY(1,1)表示自增主键,从 1 开始每次加 1;NVARCHAR用于存储中文药品名称,避免乱码;DECIMAL(10,2)表示价格保留两位小数。参数上唯一需要根据实际情况改的是文件路径,如果你把database文件夹放在了 D 盘,脚本里的FILENAME就要对应改成 D 盘路径。

2.3 连接字符串的配置和测试

数据库附加好之后,下一步是确认 C# 项目能连上。打开MSMS.csproj所在的解决方案,找到App.config或者Settings.cs之类的配置文件。如果项目里没有独立的配置文件,连接串可能直接写在某个DBHelper.cs或SqlHelper.cs里。常见做法是搜SqlConnection关键字,定位到连接串所在位置。

// 典型的连接串写法,需要根据本机实例名和认证方式调整 string connStr = "Data Source=.;Initial Catalog=MSMS;Integrated Security=True"; // 如果用的是 SQL Server 身份验证,改成: // string connStr = "Data Source=.;Initial Catalog=MSMS;User ID=sa;Password=你的密码"; using (SqlConnection conn = new SqlConnection(connStr)) { try { conn.Open(); Console.WriteLine("数据库连接成功"); } catch (SqlException ex) { // 常见错误:登录失败、实例名错误、TCP/IP 未启用 Console.WriteLine("连接失败:" + ex.Message); } }

这段代码的作用是测试连接。Data Source=.表示本机默认实例,Integrated Security=True表示用 Windows 身份验证,不需要输账号密码。如果你用的是 sa 账号,就换成User ID=sa;Password=xxx。测试时如果报「在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误」,先检查 SQL Server 服务是否启动,再检查 TCP/IP 协议是否在配置管理器里启用。SQL Server 2000 默认可能只开了命名管道,需要手动开 TCP/IP。

3. 源码结构拆解:从 YaoPinChaXun.cs 看 WinForms 数据绑定

3.1 药品查询模块的代码组织方式

YaoPinChaXun.cs是药品查询窗体的代码文件,配套的还有YaoPinChaXun.Designer.cs和YaoPinChaXun.resx。这种三文件结构是 WinForms 的标准做法:.Designer.cs放界面控件的声明和布局,.cs放业务逻辑,.resx放资源。打开YaoPinChaXun.cs,你会看到典型的 ADO.NET 查询流程:构造SqlConnection、SqlDataAdapter、DataTable,然后把DataTable绑定到DataGridView。

// 药品查询按钮的点击事件 private void btnChaXun_Click(object sender, EventArgs e) { string keyword = txtGuanJianZi.Text.Trim(); string sql = "SELECT YaoPinID, YaoPinMingCheng, ShengChanChangJia, DanJia, KuCunLiang FROM YaoPinXinXi WHERE 1=1"; if (!string.IsNullOrEmpty(keyword)) { // 参数化查询,避免 SQL 注入 sql += " AND (YaoPinMingCheng LIKE @kw OR ShengChanChangJia LIKE @kw)"; } using (SqlConnection conn = new SqlConnection(connStr)) { SqlCommand cmd = new SqlCommand(sql, conn); if (!string.IsNullOrEmpty(keyword)) { cmd.Parameters.AddWithValue("@kw", "%" + keyword + "%"); } SqlDataAdapter adapter = new SqlDataAdapter(cmd); DataTable dt = new DataTable(); adapter.Fill(dt); dgvYaoPin.DataSource = dt; } }

这段代码的逻辑是:先取用户输入的关键字,拼一个基础查询语句,如果关键字不为空就追加LIKE条件。Parameters.AddWithValue是参数化查询的写法,能防止 SQL 注入,比直接拼字符串安全。SqlDataAdapter.Fill把结果填充到DataTable,再赋给DataGridView.DataSource,界面就会自动显示数据。参数上需要注意的是LIKE的%要加在参数值里,不能加在 SQL 字符串里,否则参数化就失效了。

3.2 药品信息管理模块的增删改查实现

YaoPinXinXiGuanLi.cs对应的是药品信息管理窗体,功能上比查询多出新增、修改、删除三个操作。这类窗体的典型布局是上方一个DataGridView显示列表,下方一组TextBox和按钮用于编辑。新增操作的代码通常长这样:

// 新增药品信息 private void btnXinZeng_Click(object sender, EventArgs e) { string sql = "INSERT INTO YaoPinXinXi (YaoPinMingCheng, ShengChanChangJia, PiZhunWenHao, DanJia, KuCunLiang) " + "VALUES (@mingcheng, @changjia, @wenhao, @danjia, @kucun)"; using (SqlConnection conn = new SqlConnection(connStr)) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddWithValue("@mingcheng", txtMingCheng.Text.Trim()); cmd.Parameters.AddWithValue("@changjia", txtChangJia.Text.Trim()); cmd.Parameters.AddWithValue("@wenhao", txtWenHao.Text.Trim()); cmd.Parameters.AddWithValue("@danjia", decimal.Parse(txtDanJia.Text.Trim())); cmd.Parameters.AddWithValue("@kucun", int.Parse(txtKuCun.Text.Trim())); conn.Open(); int rows = cmd.ExecuteNonQuery(); if (rows > 0) { MessageBox.Show("新增成功"); // 刷新列表 BindData(); } } }

这段代码的关键点是ExecuteNonQuery返回受影响行数,大于 0 表示插入成功。参数化传值时要注意类型转换:decimal.Parse和int.Parse如果遇到空字符串或非数字会抛异常,常见做法是在界面上加Validating事件或者用decimal.TryParse做容错。删除操作通常是先取DataGridView当前行的YaoPinID,然后执行DELETE FROM YaoPinXinXi WHERE YaoPinID=@id。修改操作则是UPDATE语句配合WHERE条件。

3.3 项目文件里的缓存文件要不要管

解压后你会看到DesignTimeResolveAssemblyReferencesInput.cache、MSMS.csprojResolveAssemblyReference.cache、MSMS.csproj.GenerateResource.Cache这几个文件。它们不是源码,是 Visual Studio 在编译和设计时生成的缓存,可以安全删除,不影响项目运行。MSMS.cdb是设计时数据库相关的缓存文件,同样可以忽略。真正需要关注的是.csproj、.sln(如果有)、.cs和App.config。如果打开项目时提示「无法加载项目」,先检查.csproj里引用的程序集路径是否存在,常见做法是用文本编辑器打开.csproj,看<Reference>节点里的HintPath是否指向了本机不存在的目录。

4. 避坑与排查:老系统在新环境下的五个血泪经验

4.1 附加数据库时报「版本不兼容」

现象:用 SQL Server 2012 附加MSMS_Data.MDF时提示「数据库版本 539 无法打开,此服务器支持 655 及更低版本」。原因:SQL Server 2000 的数据库内部版本号是 539,而 2012 支持的最低版本是 655,高版本无法直接附加低版本文件。解决:要么装 SQL Server 2008 R2 或更低版本,要么用 SQL Server 2000 的sp_attach_db在 2000 环境里导出成 SQL 脚本,再在高版本里执行脚本重建。

4.2 登录时提示「sa 登录失败」

现象:用 sa 账号连数据库,报「用户 'sa' 登录失败」。原因:SQL Server 2000 安装时如果选了 Windows 身份验证模式,sa 账号是禁用的。解决:用 Windows 身份验证登录企业管理器,在「安全性」→「登录」里找到 sa,启用并设置密码,然后重启 SQL Server 服务。如果用的是高版本 SQL Server,还需要在「服务器属性」→「安全性」里把认证模式改成「SQL Server 和 Windows 身份验证模式」。

4.3 中文药品名称显示成乱码

现象:DataGridView里药品名称显示为问号或方块。原因:数据库字段用了VARCHAR而不是NVARCHAR,或者连接串里没有指定字符集。解决:把字段类型改成NVARCHAR,连接串里加Charset=UTF-8或者确保 C# 端用SqlParameter传NVarChar类型。如果数据已经乱了,需要重新导入。

4.4 编译时报「找不到 MSMS.csproj 引用的程序集」

现象:打开解决方案后,引用节点下出现黄色感叹号,编译报「类型或命名空间不存在」。原因:.csproj里引用的第三方 DLL 路径是原作者机器上的绝对路径,你的机器上没有。解决:删掉失效引用,重新添加本机对应版本的 DLL。如果用的是系统程序集(如System.Data.SqlClient),检查目标框架版本是否匹配,老项目通常是 .NET Framework 2.0 或 3.5,需要在新版 Visual Studio 里装对应的开发包。

4.5 查询按钮点了没反应

现象:输入关键字点查询,DataGridView不刷新。原因:可能是事件没绑定,或者connStr变量为空导致连接没建立。解决:在btnChaXun_Click第一行加断点,看是否进入事件;检查connStr是否在窗体加载时赋值;检查dgvYaoPin.DataSource是否被重新赋值后没有调用Refresh。常见做法是在BindData()方法末尾加dgvYaoPin.Refresh()。

5. 进阶用法:把默认账号 8/8 改掉,以及用 SQL 脚本做数据初始化

5.1 修改系统管理员账号和密码

系统默认管理员账号是 8,密码也是 8,这个凭据在MSMS.sql或者数据库的GuanLiYuan表里。要改的话有两种方式:一是直接进数据库改,二是改源码里的登录验证逻辑。直接改数据库更简单:

-- 查看当前管理员表 SELECT * FROM GuanLiYuan -- 修改账号和密码,假设表里有 ZhangHao 和 MiMa 字段 UPDATE GuanLiYuan SET ZhangHao = 'admin', MiMa = 'newpassword' WHERE ZhangHao = '8'

执行前先确认表名和字段名,不同版本的源码可能命名不一样。如果源码里登录验证是硬编码的(比如if (txtZhangHao.Text == "8" && txtMiMa.Text == "8")),那就需要改代码重新编译。常见做法是搜"8"这个字符串,定位到验证逻辑后改成从数据库查询。

5.2 用 SQL 脚本批量初始化药品数据

如果你不想手动一条条录入药品信息,可以写一个批量插入脚本。假设YaoPinXinXi表已经建好,可以这样批量插入:

-- 批量插入药品数据 INSERT INTO YaoPinXinXi (YaoPinMingCheng, ShengChanChangJia, PiZhunWenHao, DanJia, KuCunLiang) VALUES (N'阿莫西林胶囊', N'华北制药', N'国药准字H13020765', 12.50, 100), (N'布洛芬缓释胶囊', N'中美史克', N'国药准字H10900089', 18.00, 80), (N'头孢克肟分散片', N'广州白云山', N'国药准字H20051234', 25.80, 60), (N'维生素C片', N'东北制药', N'国药准字H21020765', 5.00, 200)

这段脚本一次插入四条药品记录,N''前缀表示 Unicode 字符串,确保中文不乱码。执行后可以在系统里直接查询到这些数据。参数上唯一要注意的是DanJia和KuCunLiang的类型要和表定义一致,如果表里是DECIMAL(10,2)和INT,这里的值就要对应。

5.3 验证系统是否跑通的三个检查点

第一个检查点是登录。用 8/8 登录,如果能进主界面,说明数据库连接和登录验证都通了。第二个检查点是查询。在药品查询界面输入「阿莫西林」,如果能查出刚才插入的数据,说明YaoPinChaXun.cs的查询逻辑和数据库表都对上了。第三个检查点是新增。在药品信息管理界面新增一条记录,然后刷新列表看是否出现,再进数据库SELECT确认数据落库。这三个点走完,整套系统的核心链路就算验证通过了。

从那以后我每次拿到这种老系统源码包,都会先备份database文件夹,再在虚拟机上装对应版本的 SQL Server,最后才动源码。这套流程帮我省掉了至少三次「附加失败导致原库损坏」的后悔药。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 1:52:57

C#物流信息管理系统源码解析:三层架构与数据库还原实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:52:41

树莓派4B+PCA9685舵机控制全攻略:从PWM抖动根源到平稳驱动

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:52:19

IEC 104测试工具实战:协议解析、参数配置与自动化调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:52:00

TSMaster实战:汽车总线报文分析与图形化显示全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:51:50

RT-Thread BSP移植到Keil5:GD32H759I-EVAL实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:51:14

计算机组成原理:DMA方式原理、三种传送方式与408考点解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华