如何在不使用OleDbCommandBuilder情况下使用OleDbDataAdapter更新Access数据库记录
我在博客园的博问和微软论坛都曾经请教了这个问题(问题链接),可能我的问题太简单,并没有获得太多解答。
到今天为止,我自己通过查找和摸索,基本把这个问题解决了,还是记录下来,供其他朋友参考。
第一次解决这么复杂的问题,我尽量用通俗的话语把问题说明白。
一、这个问题怎么来的?
众所周知,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);
}