SQL+C# 增删改查(练习)
2026/7/13 1:23:21 网站建设 项目流程

SQL代码:

if not exists(select * from sys.databases where name='productDB') 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 product

C#Winform页面设置:

C#form1代码:

注:在App.config写入

读取App.config连接字符串

需添加引用 System.Configuration;

<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> </startup> <connectionStrings> <add name="connetionString" connectionString="server=.,49671;database=ProductDB;uid=sa;pwd=123456"/> </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 1=1 "; List<SqlParameter> paramlist = new List<SqlParameter>(); 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 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; 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.Format=DateTimePickerFormat.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) { List<Category> categories = new List<Category>() { new Category(){CateName="全部",CateId=0}, new Category(){CateName="数码",CateId=1}, new Category(){CateName="服饰",CateId=2}, new Category(){CateName="食品",CateId=3} }; 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 id=@id"; using (SqlConnection conn=new SqlConnection(connStr)) { SqlCommand cmd = new SqlCommand(delsql, conn); cmd.Parameters.Add(new SqlParameter("id", pid)); conn.Open(); int rows=cmd.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) { List<Category> categories = new List<Category>() { new Category(){CateName="全部",CateId=0}, new Category(){CateName="数码",CateId=1}, new Category(){CateName="服饰",CateId=2}, new Category(){CateName="食品",CateId=3} }; 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 id=@Id"; using (SqlConnection conn=new SqlConnection(connStr)) { SqlCommand cmd=new 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.Value=Convert.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; List<SqlParameter> paramList = new List<SqlParameter>(); if (isEdit) { sql = @"Update Prod Set PName=@PName,Price=@Price,Stock=@Strock,CategoryId=@CateId, CreateTime=@CTime where id=@Id"; 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 conn=new SqlConnection(connStr)) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(paramList.ToArray()); conn.Open(); int rows=cmd.ExecuteNonQuery(); if(rows > 0) { MessageBox.Show(isEdit?"修改成功":"新增成功"); this.DialogResult=DialogResult.OK; this.Close(); } } } private void btnCancel_Click(object sender, EventArgs e) { this.DialogResult = DialogResult.Cancel; this.Close(); } } }

一、前置:SQL Server 建库建表脚本笔记

1. 作用

自动创建数据库productDB、商品表product,插入 6 条测试数据,不用手动建库建表。

小白重点记忆

  1. Identity(1,1):主键自动增长,不用自己填 id;
  2. nvarchar:存中文,varchar存英文;
  3. decimal(10,2):专门存价格,保留两位小数;
  4. go:分隔一段 SQL,分段执行;
  5. truncate:清空整张表,谨慎使用。

二、App.config 数据库配置文件笔记

作用

存放数据库账号、地址、库名,所有窗体共用,不用重复写连接地址。

连接字符串拆分小白讲解

server=.,49671;database=ProductDB;uid=sa;pwd=123456

  1. server=.,49671.代表本机 SQL,端口 49671;
  2. database=ProductDB:要操作的数据库名字;
  3. uid=sa:数据库登录账号;
  4. pwd=123456:数据库登录密码;

踩坑点

  1. <connectionStrings>必须和<startup>同级,不能嵌套;
  2. 代码里读取的名字connetionString必须和 name 完全一致;
  3. 项目必须引用System.Configuration,否则ConfigurationManager报错。

三、Category 分类实体类笔记

作用

下拉框绑定数据专用,封装「分类名称 + 分类编号」一对数据

小白理解

实体类 = 数据盒子,一个对象装一组数据,下拉框批量绑定使用。

四、Form1 主窗口笔记(商品查询、新增、编辑、删除入口)

整体功能

  1. 窗体打开自动加载分类下拉框;
  2. 多条件联合查询(名称 / 最低价 / 最高价 / 分类 / 起止上架时间);
  3. 清空日期筛选按钮;
  4. 查询、新增、编辑、删除四个功能按钮;

1. 全局变量

csharp

运行

// 只读数据库连接字符串,从配置文件读取,全局共用 private readonly string connStr = ConfigurationManager.ConnectionStrings["connetionString"].ConnectionString;

2. BindProductDate () 核心多条件查询方法(重点)

逻辑流程
  1. 基础 SQLselect * from product where 1=11=1方便拼接and条件;
  2. 每一个筛选框有内容,就拼接一段AND 条件,同时新增对应参数;
  3. 使用List<SqlParameter>存放所有参数,防止 SQL 注入;
  4. SqlDataAdapter自动打开连接,把数据填充到DataTable
  5. DataTable 绑定到表格控件,修改表头为中文。
  1. 商品名称模糊查询

csharp

运行

if (!string.IsNullOrWhiteSpace(txtPName.Text.Trim())) { sql += " And PName like @PName "; paramlist.Add(new SqlParameter("@PName",$"%{txtPName.Text.Trim()}%")); }
  • %关键词%:模糊匹配,包含这个文字就查出来;
  • 参数单独存放,不直接拼接字符串,安全防注入。
  1. 价格区间、分类、时间筛选统一逻辑:控件有值 → 拼接 SQL 条件 + 添加同名参数,一一对应。
  2. 数据库操作标准模板(固定背诵)

csharp

运行

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); // 自动打开连接,查询数据存入dt dataGridView1.DataSource = dt; // 表格展示数据 }
  • using:用完自动关闭数据库连接,不会卡死数据库;
  • SqlDataAdapter.Fill():不用手动conn.Open(),全自动读写。

3. Form1_Load 窗体加载事件

csharp

运行

private void Form1_Load(object sender, EventArgs e) { List<Category> categories = new List<Category>() { new Category(){CateName="全部",CateId=0}, new Category(){CateName="数码",CateId=1}, new Category(){CateName="服饰",CateId=2}, new Category(){CateName="食品",CateId=3} }; cbbCategory.DataSource = categories; // 绑定数据源 cbbCategory.DisplayMember = "CateName"; // 显示文字 cbbCategory.ValueMember = "CateId"; // 后台取值数字 }

窗体一打开,下拉框自动加载四个分类选项。

4. 功能按钮笔记

  1. 查询按钮 btnSearch_Click直接调用BindProductDate()重新执行查询,刷新表格;
  2. 新增按钮 btnAdd_Click

csharp

运行

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 窗体加载

  1. 绑定分类下拉框;
  2. 如果是编辑模式,调用LoadEditDate()查询旧数据回填输入框;
  3. 修改窗体标题「添加商品 / 编辑商品」。

2. LoadEditDate () 编辑回填方法(小白重点)

csharp

运行

private void LoadEditDate() { string sql = "SELECT PName,Price,Stock,CategoryId,CreateTime FROM Product WHERE id=@Id"; using (SqlConnection conn=new SqlConnection(connStr)) { SqlCommand cmd=new 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.Value=Convert.ToDecimal(dr["Stock"]); cbbCate.SelectedValue = Convert.ToInt32(dr["CategoryId"]); dtpCreate.Value = Convert.ToDateTime(dr["CreateTime"]); } dr.Close(); // 读取器必须手动关闭 } }
  • SqlDataReader:单行读取,适合编辑回填;
  • dr["字段名"]读取数据库值,必须强转对应类型赋值给控件;

3. 保存按钮 btnSave_Click(多层校验 + 新增 / 编辑双逻辑)

第一层:前端校验(拦截非法数据,不访问数据库)
  1. 商品名称不能为空;
  2. 价格必须大于 0;
  3. 库存不能负数;
  4. 必须选择有效分类(不能选全部 0);
  5. 上架时间不能早于 2000 年; 任意条件不满足弹窗提示,return直接终止保存。
第二层:区分新增 INSERT / 编辑 UPDATE

csharp

运行

if (isEdit) { // 更新SQL,根据id修改 sql = @"Update Product Set PName=@PName,Price=@Price,Stock=@Stock,CategoryId=@CateId, CreateTime=@CTime where id=@Id"; 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 1=1"; List<SqlParameter> paramList = new List<SqlParameter>(); // 拼接条件+添加参数 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 id=@Id"; 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语句"; List<SqlParameter> paramList = new List<SqlParameter>(); // 添加所有参数 using (SqlConnection conn = new SqlConnection(connStr)) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(paramList.ToArray()); conn.Open(); int rows = cmd.ExecuteNonQuery(); if(rows>0) 操作成功; }

七、高频踩坑汇总(小白必看)

  1. 字段拼写错误:Prict/CategoryId大小写、字母写错,报索引不存在;
  2. 参数名不匹配:SQL 占位符和new SqlParameter名字不一致,报「必须声明标量变量」;
  3. NumericUpDown 数值越界:数据库数字超出控件 Maximum,弹窗报错;
  4. 数据库连接字符串 IP 变更:改用.本地写法不受局域网 IP 影响;
  5. App.config 标签嵌套错误:<connectionStrings>不能写在<startup>里面;
  6. 忘记using:数据库连接不自动释放,程序长时间运行卡死;
  7. 编辑 SQL 表名写错:Update Prod少字母,执行报错找不到表;
  8. Form2 下拉框选全部 CateId=0,提交后分类筛选失效,校验拦截 0 值;

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询