C# OleDb与SqlDataAdapter增删改查实战:从老式WinForm代码到可复用DbHelper
简介这份C#增删改查源代码面向ASP.NET初学者与需要快速搭建数据库操作模块的开发者聚焦数据库连接与增删改查四大基本操作的实现。资源以OleDbConnection、OleDbCommand为核心演示了连接Access数据库、执行INSERT、DELETE、UPDATE、SELECT语句以及使用OleDbParameter进行参数化查询的完整写法并给出可复用的数据库操作固定模板帮助读者理解连接字符串配置、参数传递与DataReader读取结果等关键环节。压缩包内共1个doc文档约203KB内容以代码示例与知识点讲解为主结构紧凑便于查阅。目前已有819人学习下载适合作为课堂练习、课程设计或小型管理系统的参考素材也可用于对照排查SQL拼接与参数绑定中的常见问题。1. 从一份老式 C# 增删改查代码说起它到底能解决什么问题如果你手里维护过一个用 OleDb 连 Access 的 WinForm 小工具或者正在接手某公司十年前留下的内部管理系统那你大概率见过这种写法连接字符串硬编码在窗体里SQL 语句直接拼字符串增删改查四个按钮各写一遍。这份 C# 增删改查代码就是这类项目的典型样本——它用 OleDbConnection 连db1.mdb用 OleDbParameter 做参数化覆盖了 insert、delete、update、select 四条基本语句另外还附带了一套 SqlDataAdapter DataSet 的批量更新模板。说白了它不是教你“C# 是什么”而是给你一套能直接抄进项目里跑通的数据库操作骨架。适合谁适合刚接触 WinForm 数据库编程的新手照着复现也适合需要快速给老系统补 CRUD 功能的一线开发者。下面我按“先跑通、再拆解、最后避坑”的顺序把这份代码里真正值得注意的细节一条条拆开。2. 把 OleDb 连接和参数化查询跑通从连接字符串到四条 SQL2.1 连接字符串的构成与 OleDb 的选型理由这份代码用的是ProviderMicrosoft.Jet.OLEDB.4.0;Data Source...;Persist Security InfoFalse。为什么是 Jet 而不是 ACE因为.mdb是 Access 2003 及更早版本的格式Jet 引擎原生支持如果你拿到的文件是.accdb那就得换成Microsoft.ACE.OLEDB.12.0否则会直接抛“未注册提供程序”的异常。Persist Security InfoFalse的作用是连接打开后不再保留密码等敏感信息属于一个低成本的安全习惯。路径拼接用的是Application.StartupPath \\db1.mdb这意味着数据库文件必须放在可执行文件同级目录。调试时StartupPath指向bin\Debug发布后指向安装目录很多人第一次跑报“找不到文件”就是没把 mdb 复制过去。// 常见做法把路径拼接和连接创建封装成一个方法避免每个按钮重复写 private OleDbConnection CreateConnection() { // Application.StartupPath 在调试时是 bin\Debug发布后是 exe 所在目录 string path Application.StartupPath \\db1.mdb; // Jet 引擎对应 .mdb如果是 .accdb 要改成 Microsoft.ACE.OLEDB.12.0 string connStr ProviderMicrosoft.Jet.OLEDB.4.0;Data Source path ;Persist Security InfoFalse; return new OleDbConnection(connStr); }参数说明Provider决定用哪个数据库引擎写错就是“未注册提供程序”Data Source必须是绝对路径或相对于工作目录的路径相对路径在 WinForm 里极易翻车Persist Security Info设为 False 是推荐值。2.2 增删改三条语句的参数化写法原始代码里增删改各写了一遍OleDbParameter逻辑是对的但有个细节容易被忽略OleDb 的参数是按位置匹配的不是按名字匹配。也就是说insert into t1(name,pwd) values (a,b)里a对应第一个?位置b对应第二个。你Add的顺序必须和 SQL 里参数出现的顺序一致否则数据会串位——这是 OleDb 和 SqlClient 最大的行为差异之一。// 增参数按 SQL 中出现的顺序 AddOleDb 按位置匹配而非按名字 string sql insert into t1(name,pwd) values (a,b); OleDbParameter p1 new OleDbParameter(a, textBox1.Text); OleDbParameter p2 new OleDbParameter(b, textBox2.Text); OleDbCommand com new OleDbCommand(sql, con); com.Parameters.Add(p1); com.Parameters.Add(p2); com.ExecuteNonQuery(); // 返回受影响行数增删改都用它删和改的结构完全一样只是 SQL 不同。删是delete from t1 where name a改是update t1 set pwd a where name b。注意改语句里a是新的密码b是定位用的名字Add 顺序不能反。2.3 查询用 ExecuteReader 而不是 ExecuteNonQuery查这条和前三者不同用的是ExecuteReader()返回OleDbDataReader然后if (dr.Read())判断有没有读到行。这里有个血泪经验dr.Read()返回 bool第一次调用把游标移到第一行返回 true 表示有数据如果你写成while(dr.Read())就是遍历所有行写成if就是只判断存在性。登录场景用if是对的但别忘了用完dr.Close()否则连接池会被占住。string sql select * from t2 where Namea and Pwdb; OleDbParameter p1 new OleDbParameter(a, textBox1.Text); OleDbParameter p2 new OleDbParameter(b, textBox2.Text); OleDbCommand com new OleDbCommand(sql, con); com.Parameters.Add(p1); com.Parameters.Add(p2); OleDbDataReader dr com.ExecuteReader(); if (dr.Read()) // 只判断是否存在不遍历 { MessageBox.Show(登录通过); } dr.Close(); // 必须关闭否则连接无法复用提示OleDb 的OleDbDataReader不支持HasRows属性在某些旧版本上的稳定行为用Read()判断是最稳妥的写法。3. SqlDataAdapter DataSet 模板批量增删改的另一种思路3.1 为什么需要 DataSet 这套模板前面那套是“一条一条执行 SQL”适合单条操作。但如果你要在 DataGridView 里编辑多行然后一次性提交逐条拼 SQL 就很痛苦。这份代码里的第二套模板用的是SqlDataAdapterDataSet核心思路是Adapter 把数据从数据库拉到 DataSet你在 DataSet 里改然后 Adapter 根据每行的 RowStateAdded/Deleted/Modified自动生成对应的 INSERT/DELETE/UPDATE 语句调用da.Update(ds)一次性提交。注意这套用的是System.Data.SqlClient连的是 SQL Serverserver.;databasenorthwind;uidsa;pwdsa不是 Access。所以这份资源实际上给了你两套不同数据库的 CRUD 模板别搞混了。3.2 查询填充与 DataGridView 绑定private DataSet ds new DataSet(); private SqlConnection conn null; private SqlDataAdapter da null; // 连接字符串server. 表示本机默认实例northwind 是示例库 private const string DRIVER server.;databasenorthwind;uidsa;pwdsa; private const string sql_select select * from region; private void Form1_Load(object sender, EventArgs e) { conn new SqlConnection(DRIVER); da new SqlDataAdapter(sql_select, conn); // Adapter 持有查询语句和连接 da.Fill(ds, table); // 把结果填充到 ds 里名为 table 的 DataTable this.dataGridView1.DataSource ds.Tables[table].DefaultView; // 绑定到表格 }参数说明da.Fill(ds, table)第二个参数是 DataTable 的名字后面ds.Tables[table]要用同一个名字取。DefaultView是 DataTable 的默认视图绑定后 DataGridView 的编辑会直接反映到 DataSet 里。3.3 InsertCommand、DeleteCommand、UpdateCommand 的参数映射这三个 Command 的写法是这套模板的精髓。以 Insert 为例private bool BtnInsert() { da.InsertCommand conn.CreateCommand(); da.InsertCommand.CommandText insert into region values(id,ption); // 参数映射id 对应 DataTable 里的 regionid 列类型 Int长度 4 da.InsertCommand.Parameters.Add(id, SqlDbType.Int, 4, regionid); da.InsertCommand.Parameters.Add(ption, SqlDbType.VarChar, 10, regiondescription); int count da.Update(ds); // 提交 DataSet 里所有 Added 状态的行 return count 0; }关键在Parameters.Add的第三个参数——列名。它告诉 Adapter这个参数的值从 DataTable 的哪一列取。Delete 和 Update 里多了一个SourceVersion DataRowVersion.Original意思是“用原始值来定位行”因为删除和更新需要知道改之前的主键是什么。private bool BtnDelect() { SqlParameter sp new SqlParameter(); da.DeleteCommand conn.CreateCommand(); da.DeleteCommand.CommandText delete region where regionidid; sp da.DeleteCommand.Parameters.Add(id, SqlDbType.Int, 4, regionid); sp.SourceVersion DataRowVersion.Original; // 用原始值定位防止改过主键后找不到行 ds.Tables[table].Rows[this.dataGridView1.CurrentRow.Index].Delete(); // 标记为 Deleted int count da.Update(ds); // 提交所有 Deleted 状态的行 return count 0; }注意Rows[...].Delete()只是把行标记为 Deleted 状态并没有真正从 DataTable 移除真正删库是da.Update(ds)那一步。如果你调了Delete()但没调Update()界面上行会消失但数据库里还在。4. 避坑与排查OleDb 和 SqlDataAdapter 最容易翻车的五个点4.1 现象报“未在本地计算机上注册 Microsoft.Jet.OLEDB.4.0”原因目标机器是 64 位系统而 Jet 引擎只有 32 位版本。你的项目如果编译成 AnyCPU 并在 64 位下运行就会找不到提供程序。解决把项目的平台目标改成 x86或者在连接字符串里换用Microsoft.ACE.OLEDB.12.0需要装 Access Database Engine。我一般直接在项目属性里锁死 x86省得部署时再折腾。4.2 现象参数化查询结果串位插入的数据和预期对不上原因OleDb 按位置匹配参数你Add的顺序和 SQL 里参数出现的顺序不一致。比如 SQL 是values(a,b)你先 Add 了b再 Adda数据就反了。解决养成习惯——SQL 里参数从左到右怎么写Parameters.Add就按同样顺序加。别依赖参数名字OleDb 不认名字。4.3 现象da.Update(ds)返回 0数据没进库也没报错原因DataTable 里没有处于 Added/Modified/Deleted 状态的行。常见于你直接改了 DataGridView 但没触发 DataSet 的变更追踪或者da.InsertCommand没设置就调了 Update。解决确认da.InsertCommand、da.DeleteCommand、da.UpdateCommand都赋值了确认 DataGridView 的编辑确实写回了 DataSet绑定 DefaultView 时通常没问题但如果你手动替换了 DataSource 就会断链。4.4 现象连接打开后忘记关闭程序跑一会儿就卡死原因OleDbConnection 和 SqlConnection 都是有限资源con.Open()之后没有对应的con.Close()或using包裹连接池耗尽后后续操作全部阻塞。解决所有连接用using包起来或者至少在 finally 里 Close。原始代码里连接是窗体级字段容易忘记关我一般改成每次操作创建新连接用完即关。4.5 现象dr.Read()之后没关 DataReader再执行其他命令报“连接忙”原因OleDbDataReader 在关闭之前会独占连接同一连接上不能执行第二条命令。解决dr.Close()放在if块外面或者用using(OleDbDataReader dr com.ExecuteReader())自动释放。5. 进阶技巧把两套模板合并成一个可复用的数据库操作类原始代码把 CRUD 散落在各个按钮事件里维护起来很痛苦。我一般会抽一个DbHelper类把连接创建、参数化执行、DataSet 填充三件事封装掉。下面是一个精简版同时支持 OleDb 和 SqlClient 两种场景。public class DbHelper { private readonly string _connStr; private readonly bool _isOleDb; // true 用 OleDbfalse 用 SqlClient public DbHelper(string connStr, bool isOleDb) { _connStr connStr; _isOleDb isOleDb; } // 执行增删改返回受影响行数 public int ExecuteNonQuery(string sql, params (string name, object value)[] paras) { using (var conn _isOleDb ? new OleDbConnection(_connStr) : (DbConnection)new SqlConnection(_connStr)) { conn.Open(); using (var cmd conn.CreateCommand()) { cmd.CommandText sql; foreach (var p in paras) { var param cmd.CreateParameter(); param.ParameterName p.name; param.Value p.value ?? DBNull.Value; cmd.Parameters.Add(param); } return cmd.ExecuteNonQuery(); } } } // 查询并填充 DataTable public DataTable Fill(string sql) { using (var conn _isOleDb ? new OleDbConnection(_connStr) : (DbConnection)new SqlConnection(_connStr)) { var dt new DataTable(); var adapter _isOleDb ? (DbDataAdapter)new OleDbDataAdapter(sql, (OleDbConnection)conn) : new SqlDataAdapter(sql, (SqlConnection)conn); adapter.Fill(dt); return dt; } } }调用时就变成一行var helper new DbHelper(connStr, true); // true 表示 OleDb int rows helper.ExecuteNonQuery( insert into t1(name,pwd) values (a,b), (a, textBox1.Text), (b, textBox2.Text) );参数说明params元组把参数名和值一起传内部按顺序 Add天然规避了 OleDb 位置匹配的坑。_isOleDb开关让你同一套代码在 Access 和 SQL Server 之间切换不用改业务逻辑。验证方法很简单先跑一条 insert再用Fill(select * from t1)把数据拉回来绑到 DataGridView看新增的行在不在。如果不在检查ExecuteNonQuery的返回值是不是 0——是 0 就说明 SQL 没匹配到任何行或者参数没传对。从那以后我每次接老项目第一件事就是把散落的连接字符串和 SQL 语句全部收进一个 Helper 类强制走参数化再也没出现过串位和连接泄漏。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

PowerFocus 6000开放协议实战:从拧紧枪通信到MES数据链路集成

PowerFocus 6000开放协议实战:从拧紧枪通信到MES数据链路集成

简介:这份PDF文档是阿特拉斯(Atlas Copco)PowerFocus 6000开放协议(Open Protocol)的官方附录规范,面向需要远程控制或数据订阅控制器的应用开发者、自动化工程师与系统集成人员。文档围绕PF6000在Open Pro…

2026/10/11 16:09:28 阅读更多 →
PostgreSQL + pgvector + BM25:轻量级RAG混合检索生产实践

PostgreSQL + pgvector + BM25:轻量级RAG混合检索生产实践

刚接手一个某企业内部知识库的检索项目时,我差点按惯性给系统加一套专用向量数据库。预算、部署、运维、权限体系全都要重新走一轮,想想都头大。后来在项目复盘时发现,我们其实早就拥有了一个被低估的杀手锏:PostgreSQL 自带生态里…

2026/10/11 16:08:28 阅读更多 →
Python Trae提示词开发实战(2):2026 最新 10个自动化批处理场景 + 完整代码|TaoToken 统一 Key 接入

Python Trae提示词开发实战(2):2026 最新 10个自动化批处理场景 + 完整代码|TaoToken 统一 Key 接入

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

2026/10/11 16:08:28 阅读更多 →

最新新闻

三星ROM定制:APK与ODEX合并及反编译修改实战指南

三星ROM定制:APK与ODEX合并及反编译修改实战指南

简介:这份文档面向需要深度定制Android系统应用的开发者与ROM爱好者,聚焦APK与ODEX合并这一进阶操作,尤其针对三星I9000等闭源系统的汉化与修改场景。资源共1个docx文件,压缩包约23KB,以图文笔记形式梳理了从工具准备到…

2026/10/11 16:49:54 阅读更多 →
VisualTool.zip:本地化深度学习模型可视化调试工具

VisualTool.zip:本地化深度学习模型可视化调试工具

简介:VisualTool.zip是一套面向GIS开发人员与三维地理可视化学习者的集成工具包,聚焦Cesium与OpenLayers协同开发场景,解决二三维地图无缝切换、空间量测与动态标绘等核心需求,适用于卫星监控、风场模拟、城市规划等实战项目。资源…

2026/10/11 16:49:54 阅读更多 →
CNN卷积神经网络实战:MNIST手写识别从零到99%准确率

CNN卷积神经网络实战:MNIST手写识别从零到99%准确率

简介:面向深度学习初学者、TensorFlow入门者以及需要完成图像识别课程设计的读者,这份资源以经典MNIST手写数字识别为切入点,用一个紧凑的CNN实现展示从数据输入、卷积层、池化层、全连接层到softmax分类的完整流程。zip压缩包内共2个Python脚…

2026/10/11 16:49:54 阅读更多 →
基于Parser解析的车辆ReID:部件级特征与预训练权重实战

基于Parser解析的车辆ReID:部件级特征与预训练权重实战

简介:这份资源面向计算机视觉方向的学习者与车辆重识别(Vehicle ReID)研究者,提供一套基于Parser解析思路实现的车辆重识别Python工程,可用于智能交通、安防监控等场景下的车辆检索与匹配任务。压缩包共59个文件&#…

2026/10/11 16:49:54 阅读更多 →
手写数字识别毕业设计:从MNIST到答辩完整交付物

手写数字识别毕业设计:从MNIST到答辩完整交付物

简介:这份资源面向计算机相关专业的本科生,提供一套可直接用于毕业设计、期末大作业或课程设计的手写数字识别完整方案,帮助解决选题难、代码跑不通、论文与答辩材料无从下手的实际问题。压缩包共28个文件,约29.22MB,包…

2026/10/11 16:49:54 阅读更多 →
Spring Boot+Vue招聘系统实战:从表结构到权限控制

Spring Boot+Vue招聘系统实战:从表结构到权限控制

开发过招聘类系统的同学应该都有同感:这类项目的业务链路不算复杂,但角色多、状态多、权限多,一旦设计没想清楚,后期很容易陷入改表、加接口、调联调的循环。基于Spring Boot Vue的大学生就业招聘系统,就是典型的前后…

2026/10/11 16:48:53 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/11 14:36:54 阅读更多 →