)
SQL代码if not exists(select * from sys.databases where nameproductDB) create Database productDB; go use productDB; go create table product ( id int primary key IDentity(1,1), PName nvarchar(20) Not null, Price decimal(10,2)not null, Stock int not null, CategoryId int not null, CreateTime datetime not null ); go insert into product(PName,Price,Stock,CategoryId,CreateTime) values(苹果手机,8866.99,888,1,2024-3-25); insert into product(PName,Price,Stock,CategoryId,CreateTime) values(牛仔裤,93.29,686,2,2024-5-22); insert into product(PName,Price,Stock,CategoryId,CreateTime) values(蛋糕,28.09,587,3,2023-3-05); insert into product(PName,Price,Stock,CategoryId,CreateTime) values(虎若手机,6816.99,787,1,2020-3-25); insert into product(PName,Price,Stock,CategoryId,CreateTime) values(短袖,80.99,698,2,2000-3-25); insert into product(PName,Price,Stock,CategoryId,CreateTime) values(牛奶,8.99,748,3,2014-3-25); go select* from product go truncate table productC#Winform页面设置C#form1代码注在App.config写入读取App.config连接字符串需添加引用 System.Configuration;?xml version1.0 encodingutf-8 ? configuration startup supportedRuntime versionv4.0 sku.NETFramework,Versionv4.7.2 / /startup connectionStrings add nameconnetionString connectionStringserver.,49671;databaseProductDB;uidsa;pwd123456/ /connectionStrings /configuration实体类using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _1 { public class Category { public string CateName { get; set; } public int CateId { get; set; } } }窗体代码using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace _1 { public partial class Form1 : Form { private readonly string connStr ConfigurationManager.ConnectionStrings[connetionString].ConnectionString; public Form1() { InitializeComponent(); } public void BindProductDate() { string sql SELECT id,PName,Price,Stock,CategoryId,CreateTime FROM Product where 11 ; ListSqlParameter paramlist new ListSqlParameter(); if (!string.IsNullOrWhiteSpace(txtPName.Text.Trim())) { sql And PName like PName ; paramlist.Add(new SqlParameter(PName,$%{txtPName.Text.Trim()}%)); } if (nudMinprice.Value 0) { sql And Price MinPrice; paramlist.Add(new SqlParameter(MinPrice,nudMinprice.Value)); } if(nudMaxprice.Value 0) { sql And Price MaxPrice ; paramlist.Add(new SqlParameter(MaxPrice, nudMaxprice.Value)); } if ((int)cbbCategory.SelectedValue ! 0) { sql AND CategoryId CateId ; paramlist.Add(new SqlParameter(CateId, cbbCategory.SelectedValue)); } if (!string.IsNullOrWhiteSpace(dtpStart.Text)) { sql and CreateTime StartTime ; paramlist.Add(new SqlParameter(StartTime, dtpStart.Value.ToString(yyyy-MM-dd 00:00:00))); } if (!string.IsNullOrWhiteSpace(dtpEnd.Text)) { sql and CreateTime EndTime ; paramlist.Add (new SqlParameter(EndTime, dtpEnd.Value.ToString(yyyy-MM-dd 23:59:59))); } using (SqlConnection connnew SqlConnection(connStr)) { SqlCommand cmd new SqlCommand(sql, conn); cmd.Parameters.AddRange(paramlist.ToArray()); SqlDataAdapter adapter new SqlDataAdapter(cmd); DataTable dt new DataTable(); adapter.Fill(dt); dataGridView1.DataSource dt; dataGridView1.Columns[id].HeaderText 商品编号; dataGridView1.Columns[PName].HeaderText 商品名称; dataGridView1.Columns[Price].HeaderText 单价; dataGridView1.Columns[Stock].HeaderText 库存; dataGridView1.Columns[CategoryId].HeaderText 分类ID; dataGridView1.Columns[CreateTime].HeaderText 上架事件; } } //清空按钮 private void btnClearDate_Click(object sender, EventArgs e) { dtpStart.FormatDateTimePickerFormat.Custom; dtpStart.CustomFormat ; dtpEnd.Format DateTimePickerFormat.Custom; dtpEnd.CustomFormat ; } private void dtpStart_ValueChanged(object sender, EventArgs e) { dtpStart.Format DateTimePickerFormat.Long; } private void dtpEnd_ValueChanged(object sender, EventArgs e) { dtpEnd.Format DateTimePickerFormat.Long; } private void Form1_Load(object sender, EventArgs e) { ListCategory categories new ListCategory() { new Category(){CateName全部,CateId0}, new Category(){CateName数码,CateId1}, new Category(){CateName服饰,CateId2}, new Category(){CateName食品,CateId3} }; cbbCategory.DataSource categories; cbbCategory.DisplayMember CateName; cbbCategory.ValueMember CateId; } private void btnSearch_Click(object sender, EventArgs e) { BindProductDate(); } private void btnAdd_Click(object sender, EventArgs e) { Form2 f2 new Form2(false, 0); if (f2.ShowDialog() DialogResult.OK) { BindProductDate(); } } private void btnEdit_Click(object sender, EventArgs e) { if (dataGridView1.CurrentRow null) { MessageBox.Show(请选中一行商品); return; } int pid Convert.ToInt32(dataGridView1.CurrentRow.Cells[id].Value); Form2 f2 new Form2(true, pid); if (f2.ShowDialog() DialogResult.OK) { BindProductDate(); } } private void btnDelete_Click(object sender, EventArgs e) { if(dataGridView1.CurrentRow null) { MessageBox.Show(请选中一行商品); return; } int pid Convert.ToInt32(dataGridView1.CurrentRow.Cells[id].Value); DialogResult res MessageBox.Show(确定删除该商品吗,删除提示,MessageBoxButtons.YesNo,MessageBoxIcon.Warning); if(res!DialogResult.Yes) { return; } string delsql DELETE FROM Product where idid; using (SqlConnection connnew SqlConnection(connStr)) { SqlCommand cmd new SqlCommand(delsql, conn); cmd.Parameters.Add(new SqlParameter(id, pid)); conn.Open(); int rowscmd.ExecuteNonQuery(); if (rows 0) { MessageBox.Show(删除成功); BindProductDate(); } } } } }C#form2代码using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace _1 { public partial class Form2 : Form { private readonly string connStr ConfigurationManager.ConnectionStrings[connetionString].ConnectionString; private bool isEdit; private int productId; public Form2(bool editFlag,int pid) { InitializeComponent(); isEdit editFlag; productId pid; } private void Form2_Load(object sender, EventArgs e) { ListCategory categories new ListCategory() { new Category(){CateName全部,CateId0}, new Category(){CateName数码,CateId1}, new Category(){CateName服饰,CateId2}, new Category(){CateName食品,CateId3} }; cbbCate.DataSource categories; cbbCate.DisplayMember CateName; cbbCate.ValueMember CateId; if (isEdit) { this.Text 编辑商品; LoadEditDate(); } else { this.Text 添加商品; } } private void LoadEditDate() { string sql SELECT PName,Price,Stock,CategoryId,CreateTime FROM Product WHERE idId; using (SqlConnection connnew SqlConnection(connStr)) { SqlCommand cmdnew SqlCommand(sql, conn); cmd.Parameters.Add(new SqlParameter(id,productId)); conn.Open(); SqlDataReader dr cmd.ExecuteReader(); if (dr.Read()) { txtPName.Text dr[PName].ToString(); nudPrice.Value Convert.ToDecimal(dr[Price]); nudStock.ValueConvert.ToDecimal(dr[Stock]); cbbCate.SelectedValue Convert.ToInt32(dr[CategoryId]); dtpCreate.Value Convert.ToDateTime(dr[CreateTime]); } dr.Close(); } } private void btnSave_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(txtPName.Text)) { MessageBox.Show(商品名称不能为空); txtPName.Focus(); return; } if (nudPrice.Value 0) { MessageBox.Show(商品价格必须大于0); nudPrice.Focus(); return; } if (nudStock.Value 0) { MessageBox.Show(库存不能为负数); nudStock.Focus(); return; } if (cbbCate.SelectedValue null || (int)cbbCate.SelectedValue 0) { MessageBox.Show(请选择商品分类); cbbCate.Focus(); return; } if (dtpCreate.Value new DateTime(2000, 1, 1)) { MessageBox.Show(上架时间不能早于2000年); dtpCreate.Focus(); return; } string sql; ListSqlParameter paramList new ListSqlParameter(); if (isEdit) { sql Update Prod Set PNamePName,PricePrice,StockStrock,CategoryIdCateId, CreateTimeCTime where idId; paramList.Add(new SqlParameter(Id,productId)); } else { sql Insert into Product(PName,Price,Stock,CategoryId,CreateTime) values(PName,Price,Stock,CategoryId,CreateTime); } paramList.Add(new SqlParameter(PName,txtPName.Text.Trim())); paramList.Add(new SqlParameter(Price,nudPrice.Value)); paramList.Add(new SqlParameter(Stock,nudStock.Value)); paramList.Add(new SqlParameter(CategoryId, cbbCate.SelectedValue)); paramList.Add(new SqlParameter(CreateTime, dtpCreate.Value.ToString(yyyy-MM-dd HH:mm:ss))); using (SqlConnection connnew SqlConnection(connStr)) { SqlCommand cmd new SqlCommand(sql, conn); cmd.Parameters.AddRange(paramList.ToArray()); conn.Open(); int rowscmd.ExecuteNonQuery(); if(rows 0) { MessageBox.Show(isEdit?修改成功:新增成功); this.DialogResultDialogResult.OK; this.Close(); } } } private void btnCancel_Click(object sender, EventArgs e) { this.DialogResult DialogResult.Cancel; this.Close(); } } }一、前置SQL Server 建库建表脚本笔记1. 作用自动创建数据库productDB、商品表product插入 6 条测试数据不用手动建库建表。小白重点记忆Identity(1,1)主键自动增长不用自己填 idnvarchar存中文varchar存英文decimal(10,2)专门存价格保留两位小数go分隔一段 SQL分段执行truncate清空整张表谨慎使用。二、App.config 数据库配置文件笔记作用存放数据库账号、地址、库名所有窗体共用不用重复写连接地址。连接字符串拆分小白讲解server.,49671;databaseProductDB;uidsa;pwd123456server.,49671.代表本机 SQL端口 49671databaseProductDB要操作的数据库名字uidsa数据库登录账号pwd123456数据库登录密码踩坑点connectionStrings必须和startup同级不能嵌套代码里读取的名字connetionString必须和 name 完全一致项目必须引用System.Configuration否则ConfigurationManager报错。三、Category 分类实体类笔记作用下拉框绑定数据专用封装「分类名称 分类编号」一对数据小白理解实体类 数据盒子一个对象装一组数据下拉框批量绑定使用。四、Form1 主窗口笔记商品查询、新增、编辑、删除入口整体功能窗体打开自动加载分类下拉框多条件联合查询名称 / 最低价 / 最高价 / 分类 / 起止上架时间清空日期筛选按钮查询、新增、编辑、删除四个功能按钮1. 全局变量csharp运行// 只读数据库连接字符串从配置文件读取全局共用 private readonly string connStr ConfigurationManager.ConnectionStrings[connetionString].ConnectionString;2. BindProductDate () 核心多条件查询方法重点逻辑流程基础 SQLselect * from product where 1111方便拼接and条件每一个筛选框有内容就拼接一段AND 条件同时新增对应参数使用ListSqlParameter存放所有参数防止 SQL 注入SqlDataAdapter自动打开连接把数据填充到DataTableDataTable 绑定到表格控件修改表头为中文。商品名称模糊查询csharp运行if (!string.IsNullOrWhiteSpace(txtPName.Text.Trim())) { sql And PName like PName ; paramlist.Add(new SqlParameter(PName,$%{txtPName.Text.Trim()}%)); }%关键词%模糊匹配包含这个文字就查出来参数单独存放不直接拼接字符串安全防注入。价格区间、分类、时间筛选统一逻辑控件有值 → 拼接 SQL 条件 添加同名参数一一对应。数据库操作标准模板固定背诵csharp运行using (SqlConnection connnew SqlConnection(connStr)) { SqlCommand cmd new SqlCommand(sql, conn); cmd.Parameters.AddRange(paramlist.ToArray()); // 批量绑定所有参数 SqlDataAdapter adapter new SqlDataAdapter(cmd); DataTable dt new DataTable(); adapter.Fill(dt); // 自动打开连接查询数据存入dt dataGridView1.DataSource dt; // 表格展示数据 }using用完自动关闭数据库连接不会卡死数据库SqlDataAdapter.Fill()不用手动conn.Open()全自动读写。3. Form1_Load 窗体加载事件csharp运行private void Form1_Load(object sender, EventArgs e) { ListCategory categories new ListCategory() { new Category(){CateName全部,CateId0}, new Category(){CateName数码,CateId1}, new Category(){CateName服饰,CateId2}, new Category(){CateName食品,CateId3} }; cbbCategory.DataSource categories; // 绑定数据源 cbbCategory.DisplayMember CateName; // 显示文字 cbbCategory.ValueMember CateId; // 后台取值数字 }窗体一打开下拉框自动加载四个分类选项。4. 功能按钮笔记查询按钮 btnSearch_Click直接调用BindProductDate()重新执行查询刷新表格新增按钮 btnAdd_Clickcsharp运行Form2 f2 new Form2(false, 0); // false新增无商品id if (f2.ShowDialog() DialogResult.OK) { BindProductDate(); // 新增成功刷新表格 }ShowDialog()模态弹窗关闭后判断是否保存成功成功则刷新。 3.编辑按钮 btnEdit_Click先判断是否选中表格行读取选中商品 id打开编辑弹窗new Form2(true, pid) 4.删除按钮 btnDelete_Click判断选中行弹出确认框防止误删执行DELETE删除 SQL参数化传递商品 id删除成功刷新表格。5. 清空日期按钮 btnClearDate_Click把两个日期控件格式改成空白空格实现清空筛选时间。五、Form2 弹窗笔记新增 / 编辑共用窗口共用逻辑构造函数传参区分新增 / 编辑isEdit布尔值标记productId编辑时存商品主键。1. Form2_Load 窗体加载绑定分类下拉框如果是编辑模式调用LoadEditDate()查询旧数据回填输入框修改窗体标题「添加商品 / 编辑商品」。2. LoadEditDate () 编辑回填方法小白重点csharp运行private void LoadEditDate() { string sql SELECT PName,Price,Stock,CategoryId,CreateTime FROM Product WHERE idId; using (SqlConnection connnew SqlConnection(connStr)) { SqlCommand cmdnew SqlCommand(sql, conn); cmd.Parameters.Add(new SqlParameter(id,productId)); conn.Open(); // ExecuteReader必须手动开连接 SqlDataReader dr cmd.ExecuteReader(); // 流式读取单条数据 if (dr.Read()) // 读到一行数据才赋值 { txtPName.Text dr[PName].ToString(); nudPrice.Value Convert.ToDecimal(dr[Price]); nudStock.ValueConvert.ToDecimal(dr[Stock]); cbbCate.SelectedValue Convert.ToInt32(dr[CategoryId]); dtpCreate.Value Convert.ToDateTime(dr[CreateTime]); } dr.Close(); // 读取器必须手动关闭 } }SqlDataReader单行读取适合编辑回填dr[字段名]读取数据库值必须强转对应类型赋值给控件3. 保存按钮 btnSave_Click多层校验 新增 / 编辑双逻辑第一层前端校验拦截非法数据不访问数据库商品名称不能为空价格必须大于 0库存不能负数必须选择有效分类不能选全部 0上架时间不能早于 2000 年 任意条件不满足弹窗提示return直接终止保存。第二层区分新增 INSERT / 编辑 UPDATEcsharp运行if (isEdit) { // 更新SQL根据id修改 sql Update Product Set PNamePName,PricePrice,StockStock,CategoryIdCateId, CreateTimeCTime where idId; paramList.Add(new SqlParameter(Id,productId)); } else { // 新增插入SQL自增id不用传 sql Insert into Product(PName,Price,Stock,CategoryId,CreateTime) values(PName,Price,Stock,CategoryId,CreateTime); }第三层通用参数绑定、执行 SQL所有输入框值封装为参数批量传给cmd执行ExecuteNonQuery()增改数据 成功后设置this.DialogResult DialogResult.OK关闭弹窗通知 Form1 刷新表格。4. 取消按钮 btnCancel_Click设置返回值Cancel直接关闭窗口不保存任何数据。六、小白通用固定模板背诵模板 1查询数据填充表格Form1 使用csharp运行string sql SELECT 字段 FROM 表 where 11; ListSqlParameter paramList new ListSqlParameter(); // 拼接条件添加参数 using (SqlConnection conn new SqlConnection(connStr)) { SqlCommand cmd new SqlCommand(sql, conn); cmd.Parameters.AddRange(paramList.ToArray()); SqlDataAdapter adapter new SqlDataAdapter(cmd); DataTable dt new DataTable(); adapter.Fill(dt); dataGridView1.DataSource dt; }模板 2单条数据读取回填控件Form2 编辑使用csharp运行string sql SELECT 字段 FROM 表 WHERE idId; using (SqlConnection conn new SqlConnection(connStr)) { SqlCommand cmd new SqlCommand(sql, conn); cmd.Parameters.Add(new SqlParameter(Id, 主键值)); conn.Open(); SqlDataReader dr cmd.ExecuteReader(); if(dr.Read()) { // dr[字段]赋值给控件 } dr.Close(); }模板 3新增 / 修改 / 删除执行模板csharp运行string sql INSERT/UPDATE/DELETE语句; ListSqlParameter paramList new ListSqlParameter(); // 添加所有参数 using (SqlConnection conn new SqlConnection(connStr)) { SqlCommand cmd new SqlCommand(sql, conn); cmd.Parameters.AddRange(paramList.ToArray()); conn.Open(); int rows cmd.ExecuteNonQuery(); if(rows0) 操作成功; }七、高频踩坑汇总小白必看字段拼写错误Prict/CategoryId大小写、字母写错报索引不存在参数名不匹配SQL 占位符和new SqlParameter名字不一致报「必须声明标量变量」NumericUpDown 数值越界数据库数字超出控件 Maximum弹窗报错数据库连接字符串 IP 变更改用.本地写法不受局域网 IP 影响App.config 标签嵌套错误connectionStrings不能写在startup里面忘记using数据库连接不自动释放程序长时间运行卡死编辑 SQL 表名写错Update Prod少字母执行报错找不到表Form2 下拉框选全部 CateId0提交后分类筛选失效校验拦截 0 值