我在博客园的博问和微软论坛都曾经请教了这个问题(问题链接),可能我的问题太简单,并没有获得太多解答。

到今天为止,我自己通过查找和摸索,基本把这个问题解决了,还是记录下来,供其他朋友参考。

第一次解决这么复杂的问题,我尽量用通俗的话语把问题说明白。

一、这个问题怎么来的?

众所周知,Access是典型的关系型数据库,数据库各表或多或少的都有对应关系。对数据库进行操作,往往就不能只操作一个表,最常见的场景就是:在使用基于多表的联合查询之后,依照特定顺序更新各关联表数据。

网上的帖子,内容基本上都是OleDbDataAdapter和OleDbCommandBuilder的联合使用,这样使用当然很方便,但这样使用一个致命问题就是:仅能对单个表进行操作。一旦涉及到多个表,便会出现如下的问题:

一般,遇到这种情况,很多帖子就会介绍使用OleDbCommand,即直接使用SQL命令更新数据库。

但是这样做太硬核,它要满足3个苛刻条件:

1、手动开启、关闭数据库连接,

2、直接编写sql命令,

3、保证在命令执行期间一直与数据库保持连接,不能中断。

整个操作风险很高,且灵活性很差。

因此才会寻求如何单独使用OleDbDataAdapter更新Access数据库记录。

二、解决该问题前的知识储备

在了解解决方法之前,我认为先要搞懂几个问题:

2.1 OleDBDataAdapter如何处理数据?

OleDBDataAdapter可以填充DataSet,也可直接填充DataTable。

即:DataAdapter填充→DataSet→DataTable→DataRow 或者 DataAdapter填充→DataTable→DataRow

但不论那种方式,最终都要在DataRow处理数据。只有在DataRow中变更了的数据,才会在DataAdapter的Update方法执行后更新到数据库。在这里,记录的“修改”、“添加”、“删除”都认为是“变更”。

2.2 关于Table表名称

SqlDataAdapter类与OleDbDataAdapter类的Fill方法填充DataSet中表名称,默认是Table, Table1, Table2……,不是数据库中的表名。

想DataSet中表名称设置成跟数据库中表名称一样的,可以通过OleDbDataAdapter类TableMappings属性的Add方法实现。

TableMappings.Add方法,第一个参数是Fill DataSet时默认的表名,第二参数是指定的表名,可以根据需要自定义。

2.3 DataTable主键设定

在定义DataRow前,需要为DataTable指定主键,Access数据库中的主键定义传不过来。

2.4 控制更新顺序及选择特定类型DataRow

可以使用DataTable的Select方法来返回仅引用具有特定 DataRow 的 RowState 数组,然后可以将返回的 DataRow 数组传递给 Update 的 DataAdapter 方法来处理已修改的行。 通过指定要更新的行的子集,可以控制处理插入、更新和删除的顺序。

例如:处理表中“已删除”的行
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

知道上面这些,就可以着手来解决问题了。

三、完整的解决代码

3.1 定义连接字符串和sql查询语句

1 readonly OleDbConnection connection = new OleDbConnection()
2 {
3 ConnectionString = Properties.Settings.Default.myConnString
4 //myConnString内存放着Access数据库连接字符串
5 };
6 string selectCommandText = "SELECT T0101_公司情况表.公司名称_PK, T0101_公司情况表.统一社会信用代码, T0101_公司情况表.公司地址, T0301_fdc证件信息表.证件编号 FROM T0101_公司情况表 INNER JOIN T0301_fdc证件信息表 ON T0101_公司情况表.公司名称_PK = T0301_fdc证件信息表.公司名称_FK;";//基于多表的联合查询,有这种查询的时候OleDbCommandBuilder就无法使用。

3.2 单独使用OleDbDataAdapter更新Access数据库的完整代码

private void Btn_UpdateByAdapter_Click(object sender, RoutedEventArgs e)
{
/****方法2:使用OleDBDataAdapter更新数据库****/
OleDbCommand selectCommand = new OleDbCommand(selectCommandText, connection);
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(selectCommand);
dataAdapter.TableMappings.Add("Table", "T0101_公司情况表");
//DataAdapter类的Fill方法填充DataSet中表名称,默认是Table, Table1, Table2……Add方法第一个参数是Fill DataSet时默认的表名,第二参数是指定的表名,可以根据需要自定义(一般定义为数据库中的表名)。
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
DataTable table = dataSet.Tables["T0101_公司情况表"];
table.PrimaryKey = new DataColumn[] { table.Columns["公司名称_PK"] };//必须要指定主键
DataRow dataRow = table.Rows.Find("房县大唐盛世置业有限公司");
Random random = new Random();
dataRow["统一社会信用代码"] = "信用代码" + random.Next(1, 99);
OleDbCommand updateCommand = new OleDbCommand()
{
CommandText = "UPDATE T0101_公司情况表 SET 统一社会信用代码 = ? WHERE 公司名称_PK = ?",
Connection = connection
};
OleDbParameter parameter1 = new OleDbParameter()
{
ParameterName = "@统一社会信用代码",//虽然在Access中用途不大,但还是建议应按照查询参数的要求写。
OleDbType = OleDbType.Char,
Size = 18,
SourceColumn = "统一社会信用代码"
};
updateCommand.Parameters.Add(parameter1);
updateCommand.Parameters.Add("公司名称_PK", OleDbType.VarChar, 200, "公司名称_PK"); dataAdapter.UpdateCommand = updateCommand;
dataAdapter.Update(dataSet);
}

如何在不使用OleDbCommandBuilder情况下使用OleDbDataAdapter更新Access数据库记录的更多相关文章

  1. mysql-unsha1:在未知密码情况下,登录任意MYSQL数据库

    摘要 这个POC用于在不知道明文密码的情况下对启用了密码安全认证插件(默认开启插件:mysql_native_password)的MYSQL数据库进行登录. 前提条件为: 1.为了获取到已知用户的ha ...

  2. AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

    AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. AJAX 是与服 ...

  3. java-int类型:int默认为0导致更新操作未赋值的情况下将值更新为0

    日常开发中,做更新操作的时候的处理方法为:当这个字段有值则更新,没有值就不更新,在mybatis的xml中表现为: <!-- 修改记录,只修改只不为空的字段 --> <update ...

  4. 使用EF Model First创建edmx模型,数据库有数据的情况下,如何同时更新模型和数据库

    使用"EF Model First",我们可以很直观地在edmx文件中创建数据模型,并根据模型生成数据库,整个过程快速而高效.可当数据库中有了一定的数据量,同时,可能需要对模型中字 ...

  5. 在不重装系统的情况下撤底删除oracle数据库及oralce的相关软件

    先从控制面板删除oracle的相关应用及数据库, 删除系统变量 ORACLE_OEM_CLASSPATH=%JAVA_HOME%\lib\ext\access-bridge-64.jar;%JAVA_ ...

  6. 如何在不改SQL的情况下优化数据库

    主题简介 在数据库运维中我们会遇到各种各样的问题,这些问题的根源可能很明显,也可能被某种表象掩盖而使我们认不清.所以运维面临的两大问题就是,第一我们没有看清本质,第二应用不允许修改.那么我们如何解决这 ...

  7. SQL Server 在缺少文件组的情况下如何还原数据库

    SQL Server 在缺少文件组的情况下如何还原数据库 一.背景 我有一个A库,由于a,b两张表的数据量比较大,所以对表进行分区:在把A库迁移到一个新的集群上去,我只备份了A库的主分区过去进行还原为 ...

  8. 如何在删除ibdata1和ib_logfile的情况下恢复MySQL数据库

    昨天,有个朋友对公司内部使用的一个MySQL实例开启binlog,但是在启动的过程中失败了(他也没提,为何会失败),在启动失败后,他删除了ibdata1和ib_logfile,后来,能正常启动了,但所 ...

  9. 排版紧凑情况下IOS 浏览器的文字部分选中问题

    一.需求 一个每一项都是图文混排的列表页,在需要对其中的某一部分文字进行选中copy的时候,IOS个二货每次都是直接选中了整个列表项,无论怎么操作它的选框都没有办法做到部分选中. 这是我本周遇到遇到的 ...

随机推荐

  1. C#LeetCode刷题之#374-猜数字大小(Guess Number Higher or Lower)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3993 访问. 我们正在玩一个猜数字游戏. 游戏规则如下: 我从 ...

  2. C#LeetCode刷题之#680-验证回文字符串 Ⅱ​​​​​​​(Valid Palindrome II)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3961 访问. 给定一个非空字符串 s,最多删除一个字符.判断是否 ...

  3. C#LeetCode刷题之#453-最小移动次数使数组元素相等(Minimum Moves to Equal Array Elements)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3877 访问. 给定一个长度为 n 的非空整数数组,找到让数组所有 ...

  4. C#LeetCode刷题之#830-较大分组的位置(Positions of Large Groups)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3750 访问. 在一个由小写字母构成的字符串 S 中,包含由一些连 ...

  5. PHP基础之常量与变量

    1.变量:用来存储信息的空间大小 $var 2.常量:定义之后不可以更改,标识符,并且给其赋值,常量是全局,在整个页面中均可使用,常量一般有英文字母.下划线.数字组成,开头不能是数字和$ 使用defi ...

  6. Redis哨兵模式的配置

    绪论 现有三台设备,192.168.137.11.192.168.137.12和192.168.137.13,要求在三台设备上实现redis哨兵模式,其中192.168.137.11为master,其 ...

  7. python基础 Day6

    python Day6 id 可以获得python的内存地址 id的举例子 a=100 print(id(a)) #140712544153072 这里就是该对象的内存地址 is 判断的是比较内存地址 ...

  8. CSS动画实例:移动的眼珠子

    适当地利用CSS的box-shadow可以构造图形,然后可以对构造的图形添加动画效果.下面我们通过移动的眼珠子.圆珠一二三.一分为四.四小圆旋转扩散等实例来体会box-shadow属性在动画制作中的使 ...

  9. 月历输出php代码

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. python编程中的并发------协程gevent模块

    任务例子:喝水.吃饭动作需要耗时1S 单任务:(耗时20s) for i in range(10): print('a正在喝水') time.sleep(1) print('a正在吃饭') time. ...