SQL+C# 增删改查(练习)

SQL代码:

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;

cs 复制代码
<?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>

实体类:

cs 复制代码
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; }
    }
}

窗体代码:

cs 复制代码
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代码:

cs 复制代码
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. 基础 SQL select * 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 值;
相关推荐
2301_800256111 小时前
第七章 空间存储与索引 知识点梳理-2
数据库·sql·oracle
草莓熊Lotso1 小时前
【Redis 初阶】 从分布式演进背景到环境搭建全解析
数据库·人工智能·redis·分布式·缓存
倔强的石头_1 小时前
优化器为什么敢把你写的 LEFT JOIN 悄悄改掉?-国产化金仓 KES 优化器设计思路拆解
数据库
学习-学习1 小时前
PostgreSQL 19 Beta 值得测吗?并行 Autovacuum、REPACK 到 WAIT FOR LSN 看生产影响
数据库·postgresql
何中应2 小时前
Postgres 搭建主从集群
数据库·postgresql·集群·开发工具
数字新视界2 小时前
档案库房环境安全监控解决方案
大数据·运维·数据库·物联网·环境监控系统
嘘神秘用11 小时前
布:AI 驱动的 Redis 客户端,更快、更直观
数据库·人工智能·redis
东北小狐狸-Hellxz13 小时前
Redis 哨兵搭建+ACL权限控制
数据库·redis