使用SqlDataAdapter批量更新数据

应用说明

        数据适配器有SelectCommand、InsertCommand、DeleteCommand、UpdateCommand四种命令对象。分别给每种命令对象赋予相应的命令,就可以用数据适配器对数据集进行更新操作了。

         使用数据适配器进行更新有一个很重要的方法,这里需要特别的说明一下。

SqlDataAdapter一般和SqlCommandBuilder配合使用,可以省略很多SQL语句的编写工作。

string source ="server=.;integratedsecurity=SSPI;database=wl_client";

string select ="select * fromWlcStore_StoreInfo where storecode = '001'";

SqlConnection conn =new SqlConnection(source);

// 构造适配器的时候提供了一个查询语句,此时会自动初始化适配器的SelectCommand,此时适配器的其他几个命令对象未初始化,此时只能填充数据集,还不能更新数据集。

SqlDataAdapter da =new SqlDataAdapter(select, conn);

DataSet ds =new DataSet();

da.Fill(ds, "Customers");

// 注意此语句, 用适配器去初始化一个SqlCommandBuilder,就这么简单的一个语句,运行库自动为我们完成适配器的三种更新操作的命令对象的初始化工作,运行库自动生成SQL语句,前面提供的查询语句就是运行库生成更新操作SQL语句的依据,所以第一步的查询语句不能少。

SqlCommandBuilder scb =new SqlCommandBuilder(da);

 

// 在数据集中新增一行

DataRowdr = ds.Tables[0].NewRow();

dr[0] ="002";

dr[1] ="新增仓库一";

ds.Tables[0].Rows.Add(dr);

 

// 修改数据集第一行,第一列的值

ds.Tables[0].Rows[0][0]= "00001";

 

// 删除数据集中第二列的值

ds.Tables[0].Rows[1].Delete();

// 直接一个更新语句,ds中所有的更新都会反映到数据库中。

da.Update(ds,"Customers");

         下面解释一个这个语句的原理:SqlCommandBuilder为我们自动生成了更新操作语句,包括插入操作,修改操作和删除操作,语句的生成依据是我们提供的查询语句(包含数据表,列信息)。DataRow可以记录行中每一列的版本状态值(初始值,默认值,修改值等)。那么在执行Update这个语句时,运行库会自动查找每一行的主键的初始值,根据这个值在数据库中定位到唯一的一行,然后把这一行的修改保存起来,即使这一行的主键值发生了改变,运行库还是能定位到正确的行上进行修改。

        从上面的描述,我们可以看到,要使用这个操作,必须要确保更新的表必须包含主键,否则运行库无法准确定位。

这个方法非常适合那种不要每个操作都实时反映到数据库,操作完成后集中点击提交按钮同一保存的那种场景。


注意事项

如果使用SqlDataAdapter来查询数据返回给DataSet或者DataTable时需要注意以下几点:

1、如果SqlDataAdapter的SelectCommand的连接并没有打开,使用SqlDataAdapter的Fill方法时会自动打开数据库连接,并在方法执行完毕自动关闭连接。如果连接在使用Fill方法之前已经打开,方法执行结束后会保持连接的现有状态,不会关闭连接。

2、如果你在同一个Connection上有一系列的连续操作,例如执行多个Fill操作,你应该在最开始使用Connection的Open()方法打开连接,避免使用Fill方法时执行额外的打开连接/关闭连接操作,从而提高了程序的性能。

3、在使用SqlDataAdapter中的SqlCommand对象时,你可以重复的使用同一个SqlCommand去多次执行相同类型的操作,比如说执行多次查询,但是不要使用同一个SqlCommand去执行不同类型的操作。 

4、当SqlDataReader没有关闭之前,数据库连接会一直保持open状态,所以在使用SqlDataReader时,使用完毕应该马上调用SqlDataReader.Close()关闭它。

5、一个连接只能被一个SqlDataReader使用,这也是为什么要尽早关闭SqlDataReader的原因。

6、使用完SqlDataReader后,你可以在程序中显示的调用数据库连接对象的Close方法关闭连接,也可以在调用Command对象的 ExecuteReader方法时传递CommandBehavior.CloseConnection 这个枚举变量,这样在调用SqlDataReader的Close方法时会自动关闭数据库连接。

7、使用SqlDataReader时尽量使用和数据库字段类型匹配的方法来取得相应的值,比如对于整形的字段使用GetInt32,对字符类型的字段使用GetString。这样会减少因为类型不一致而额外增加的类型转换操作。

8、使用SqlDataReader获取多条记录时,如果没有访问到取出记录的末尾时想要关闭SqlDataReader,应该先调用Command对象的 Cancel方法,然后再调用SqlDataReader的Close方法。Command对象的Cancel方法使得数据库不再把 SqlDataReader中未访问的数据发送到调用端,如果不调用此方法直接关闭SqlDataReader,数据库会发送和 SqlDataReader未访问数据等长的空数据流到调用端。

9、如果想通过SqlCommand的ExecuteReader方法获取存储过程的返回值或者输出参数,必须先调用SqlDataReader的Close方法后,才能获取输出参数的值或者返回值。

10、如果使用SqlDataReader只返回一条记录,那么在调用Command的ExecuteReader方法时,指定

CommandBehavior.SingleRow参数,这个参数的是否使用对SQL Server .NET Data Provider没有什么影响,但是当你使用OLE DB .NET Data Provider时,指定这个参数后,DataPrivider内部将使用IRow接口,而不是使用相对来说耗费资源的IRowSet接口。


应用场景

1.    有时候需要缓存的时候,比如说在一个商品选择界面,选择好商品,并且进行编辑/删除/更新后,

最后一并交给数据库,而不是每一步操作都访问数据库,因为客户选择商品可能进行n次编辑/删除

更新操作,如果每次都提交,不但容易引起数据库冲突,引发错误,而且当数据量很大时在用户执行

 效率上也变得有些慢。

2.      有的界面是这样的有的界面是这样的,需求要求一定用缓存实现,确认之前的操作不提交到库,点击

页面专门提交的按钮时才提交商品选择信息和商品的其它信息. 我经常遇到这样的情况

3.      有些情况下只往数据库里更新,不读取. 也就是说没有从数据库里读,sqldataadapter也就不知道是

更新哪张表了,调用update就很可能出错了。这样的情况下可以用sqlcommandbuilder 了.
        

4.      只能更新一个表,不能更新两个或两个以上相关联的表, 表中必须有主键

5.      更新的表中字段不能有image类型的

6.      优点:节省代码量,节省时间,这个方法可以代替所有的:  更新/删除/插入操作语句

7.       缺点:访问两次数据库(select * tablename,就是这句,要确认是哪个表,除非是很大的数据量,一般是感觉不到的),效率有些慢


使用事务

       适配器也可以和事务配合使用,同时提交多个表的更新动作。参照下面这个方法,可以把适配器和事务关联起来。


public void datasetupdate(dataset ds, sqlconnection sqlconnect, string tablename, string sqlstr,sqltransaction sqltrans)
        {
            try
            {
                sqldataadapter adapter = new sqldataadapter(sqlstr, sqlconnect);


                sqlcommandbuilder cmdbuilder = new sqlcommandbuilder(adapter);

               //创建sqldataadapter 对像的command对像,并将连接对像及事务对像绑定到command对像上

                adapter.deletecommand = new sqlcommand("", sqlconnect, sqltrans);
                adapter.insertcommand = new sqlcommand("", sqlconnect, sqltrans);
                adapter.updatecommand = new sqlcommand("", sqlconnect, sqltrans);
                adapter.selectcommand = new sqlcommand(sqlstr, sqlconnect, sqltrans);

               //使用getdeletecommand将相对应的sqlcommand对像传入

                adapter.deletecommand = cmdbuilder.getdeletecommand();
                adapter.insertcommand = cmdbuilder.getinsertcommand();
                adapter.updatecommand = cmdbuilder.getupdatecommand();
                //cmdbuilder.refreshschema();
                int val = adapter.update(ds, tablename);
                ds.tables[tablename].acceptchanges();
            }
            catch
            {

                throw;
            }
        }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章