SqlDataAdapter.Update批量数据更新
使用SqlDataAdapter.Update可以方便地对数据库进行快速、批量数据更新。我们最常用的多条数据更新方法是使用循环多次执行SQL语句或存储过程,这样虽然方便,但由于连接和数据传递要在服务器和客户端多次来往,大大增加了整个过程的时间,当数据越大时越明显!
下面对SqlDataAdapter.Update作个简单的演示介绍吧。
测试环境:SqlServer2008+VS2010+WinXP
1.建立测试数据库和表
CREATE DATABASE [TEST]
GO
USE [Test]
GO
CREATE TABLE [Student](
[SNo] [int] NOT NULL,
[SName] [nvarchar](50) ,
[SAge] [int]
) O
GO
2.建立解决方案和项目
使用SqlDataAdapter.Update更新有三种方式,即SqlCommandBuiler自动生成更新,使用配置数据源方式更新,手动编写命令。
SqlCommandBuiler方式:
代码1:
private void Form1_Load(object sender, EventArgs e)
{
string constr = "server=localhost\\sqlserver2008;initial catalog=test;uid=sa;pwd=123456;";
SqlConnection conn = new SqlConnection(constr);
//设置select查询命令,SqlCommandBuilder要求至少有select命令
SqlCommand selectCMD = new SqlCommand("select top 0 SNo,SName,SAge from Student", conn);
DataTable dt = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter(selectCMD);
//上面的语句中使用select 0,不是为了查询出数据,而是要查询出表结构以向DataTable中填充表结构
sda.Fill(dt);
//给DataTable添加10条记录
for(int i=1;i<=10;i++)
dt.Rows.Add(new object[] { i, "aaa"+i, 20+i });
SqlCommandBuilder scb = new SqlCommandBuilder(sda);
//执行更新
sda.Update(dt.GetChanges());
//使DataTable保存更新
dt.AcceptChanges();
}
//执行后查看表中数据,如图:

上面我只作了插入操作,那现在将Select中的Top 0 去掉,把表中的数据全部加载到DataTable然后执行删除和更新操作
代码2
private void Form1_Load(object sender, EventArgs e)
{
string constr = "server=localhost\\sqlserver2008;initial catalog=test;uid=sa;pwd=123456;";
SqlConnection conn = new SqlConnection(constr);
//设置select查询命令,SqlCommandBuilder要求至少有select命令
SqlCommand selectCMD = new SqlCommand("select SNo,SName,SAge from Student", conn);
DataTable dt = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter(selectCMD);
//上面的语句中使用select 0,不是为了查询出数据,而是要查询出表结构以向DataTable中填充表结构
sda.Fill(dt);
//先更新第1,2条数据的SName和SAge
dt.Rows[0]["SName"] = "AAA";
dt.Rows[0]["SAge"] = 33;
dt.Rows[1]["SName"] = "BBB";
dt.Rows[1]["SAge"] = 444;
//然后使用RemoveAt删除第3,4条数据
dt.Rows.RemoveAt(2);
dt.Rows.RemoveAt(3);
//使用Delete删除
//dt.Rows[2].Delete();
//dt.Rows[3].Delete();
SqlCommandBuilder scb = new SqlCommandBuilder(sda);
//执行更新
sda.Update(dt.GetChanges());
//使DataTable保存更新
dt.AcceptChanges();
}
执行后将出错,错误信息“对于不返回任何键列信息的 SelectCommand,不支持 UpdateCommand 的动态 SQL 生成。”
出错原因是建表时没有设置主键。主键唯一标识一行数据,SqlCommandBuilder是根据DataTable每行的RowState及对应的主键来生成命令的,没有主键就无法确定删除哪条数据,当然不可能根据其他列来删除,因为其他列可能重复,这样会删除多行数据,很可能执行后不是你想要的结果,这种不确定性的对数据的操作方法,微软当然不可能提供给你!
那就给表添加主键吧
执行如下SQL语句:
alter table student
add constraint PK_Student
primary key(SNo)
再次执行上面的代码2.
执行后

我们发现第1,2行数据更新了,但是第3,4行却没有删除。这是怎么回事呢?
先不急,把代码2中的
dt.Rows.RemoveAt(2);
dt.Rows.RemoveAt(3);
注释掉,同时把
//dt.Rows[2].Delete();
//dt.Rows[3].Delete();
的注释去掉,使之执行Delete方法而不是RemoveAt方法
再看看结果:

第3,4行已经删除。
原因是:使用RemoveAt或Remove会将数据真正的从DataTable中删除,而使用Delete则不会,而仅是把当前行的RowState值置为deleted.
前面说过SqlCommandBuilder是根据RowState和主键来生成命令的,RemoveAt/Remove把数据删除了,怎么能找到主键和RowState呢?
所以使用SqlCommandBuilder时应该注意的2点:表要有主键,应使用delete方法删除行.
手写命令方法:
代码3:
private void Form1_Load(object sender, EventArgs e)
{
string constr = "server=localhost\\sqlserver2008;initial catalog=test;uid=sa;pwd=123456;";
SqlConnection conn = new SqlConnection(constr);
//设置select查询命令
SqlCommand selectCMD = new SqlCommand("select SNo,SName,SAge from Student", conn);
//Insert命令
SqlCommand insertCMD = new SqlCommand("insert into Student(SNo,SName,SAge) values(@SNo,@SName,@SAge)", conn);
//Update命令
SqlCommand updateCMD = new SqlCommand("update Student Set SName=@SName,SAge=@SAge where SNo=@SNo", conn);
//Delete命令
SqlCommand deleteCMD = new SqlCommand("delete from Student where SNo=@SNo", conn);
//给Insert,Update,Delete三个命令添加参数
SqlParameter paraSNo1, paraSNo2, paraSNo3;//第二个指定参数值的来源,这里的SNo是指DataTable中的列名
paraSNo1 = new SqlParameter("@SNo", "SNo");
paraSNo2 = new SqlParameter("@SNo", "SNo");
paraSNo3 = new SqlParameter("@SNo", "SNo");
paraSNo1.SourceVersion = DataRowVersion.Current;//指定SourceVersion确定参数值是列的当前值(Current),还是原始值(Original),还是建议值(Proposed)
paraSNo2.SourceVersion = DataRowVersion.Current;
paraSNo3.SourceVersion = DataRowVersion.Current;
SqlParameter paraSName1, paraSName2, paraSName3;
paraSName1 = new SqlParameter("@SName", "SName");
paraSName2 = new SqlParameter("@SName", "SName");
paraSName3 = new SqlParameter("@SName", "SName");
paraSName1.SourceVersion = DataRowVersion.Current;
paraSName2.SourceVersion = DataRowVersion.Current;
paraSName3.SourceVersion = DataRowVersion.Current;
SqlParameter paraSAge1, paraSAge2, paraSAge3;
paraSAge1 = new SqlParameter("@SAge", "SAge");
paraSAge2 = new SqlParameter("@SAge", "SAge");
paraSAge3 = new SqlParameter("@SAge", "SAge");
paraSAge1.SourceVersion = DataRowVersion.Current;
paraSAge2.SourceVersion = DataRowVersion.Current;
paraSAge3.SourceVersion = DataRowVersion.Current;
insertCMD.Parameters.AddRange(new SqlParameter[] { paraSNo1, paraSName1, paraSAge1 });
updateCMD.Parameters.AddRange(new SqlParameter[] { paraSNo2, paraSName2, paraSAge2 });
deleteCMD.Parameters.AddRange(new SqlParameter[] { paraSNo3, paraSName3, paraSAge3 });
DataTable dt = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter(selectCMD);
sda.Fill(dt);
//插入2条数据
dt.Rows.Add(new object[] { 11, "aa11", 31 });
dt.Rows.Add(new object[] { 12, "aa12", 32 });
//先更新第1,2条数据的SName和SAge
dt.Rows[0]["SName"] = "CCC";
dt.Rows[0]["SAge"] = 55;
dt.Rows[1]["SName"] = "DDD";
dt.Rows[1]["SAge"] = 66;
//使用Delete删除第3,4条数据
dt.Rows[2].Delete();
dt.Rows[3].Delete();
SqlCommandBuilder scb = new SqlCommandBuilder(sda);
//执行更新
sda.Update(dt.GetChanges());
//使DataTable保存更新
dt.AcceptChanges();
}
执行结果:

可以看到
第SNo为11,12的数据是新增的。
原来SNo为1,2的数据中SName已经从AA,BB更改为CC,DD,另一列SAge从33,44更改为55,66。
原来SNo为5,6也就是第3,4条数据已经被删除
//
原文链接:http://www.cnblogs.com/moss_tan_jun/archive/2011/11/26/2263992.html
SqlDataAdapter.Update批量数据更新的更多相关文章
- SqlBulkCopy(批量复制)使用方法 && SqlDataAdapter Update
SqlBulkCopy提供了一种将数据复制到Sql Server数据库表中高性能的方法.SqlBulkCopy 包含一个方法 WriteToServer,它用来从数据的源复制数据到数据的目的地. Wr ...
- 【C#-批量插入数据到数据库】DataTable数据批量插入数据的库三种方法:SqlCommand.EcecuteNonQurery(),SqlDataAdapter.Update(DataTable) ,SqlBulkCopy.WriteToServer(Datatable)
第一种方法:使用SqlCommand.EcecuteNonQurery() 效率最慢 第二种方法:使用SqlDataAdapter.Update(DataTable) 效率次之 第三种方法:使用 ...
- sql server merge into 与update 批量更新1 百万测试数据的性能比较
1. 1百万的测试数据的生成 declare @index int; begin set @index=0; while @index<1000000 begin insert int ...
- update批量更新某一列成其它列对应的值【原】
update批量更新某一列成其它列对应的值 postgresql 标准sql语句 update AA set name = BB.name , AA.sex = BB.sex from BB wher ...
- 批量 1 insert into select 2 sqldataadapter.update 3 SELECT INTO FROM (要求目标表不存在) 4 AddRange(ef) 5 MySqlBulkLoader.Load() 6 BatchInsert 7 insert bulk
insert into a(col1,col2) select top 1 '1','2' from a union select top 1 '3','4' from a SELECT IN ...
- SqlDataAdapter.Update()方法与SqlCommandBuilder(转)
用SqlDataAdapter操纵数据集时最常用到的就是Fill()与Update()方法.Fill()填充DataSet或DataTable,而Update()就是将DataSet或DataTabl ...
- hisql orm update表数据更新文档
更新 HiSql数据更新 HiSql 提供了好几种数据更新的方式下面一一介绍一下 如果你的表中增加了这四个字段 字段 描述 类型 CreateTime 创建时间 DateTime CreateName ...
- Oracle forall bulk collect批量数据更新
对于数据量较大的插入操作可采用此种方法操作,注意: limit减少内存占用,如果数据量较大一次性全部加载到内存中,对PGA来说压力太大,可采用limit的方法一次加载一定数量的数据,建议值通常为100 ...
- 【转】【MySql】Update批量更新与批量更新多条记录的不同值实现方法
批量更新 mysql更新语句很简单,更新一条数据的某个字段,一般这样写: UPDATE mytable SET myfield = 'value' WHERE other_field = 'other ...
随机推荐
- 网易云课堂_程序设计入门-C语言_第二周:判断_2信号报告
2 信号报告(5分) 题目内容: 无线电台的RS制信号报告是由三两个部分组成的: R(Readability) 信号可辨度即清晰度. S(Strength) 信号强度即大小. 其中R位于报告第一 ...
- iOS 开发的几种手势
今天为大家介绍一下IOS 的七种手势,手势在开发中经常用到,所以就简单 通俗易懂的说下, 话不多说,直接看代码: // 初始化一个UIimageView UIImageView *imageView ...
- php将文件夹打包成zip文件
function addFileToZip($path,$zip){ $handler=opendir($path); //打开当前文件夹由$path指定. while(($filenam ...
- jQuery学习笔记(一)——基础选择器、过滤选择器、表单选择器
$()就是jQuery中的函数,它的功能是获得()中指定的标签元素.如演示样例中$("p")会得到一组P标签元素,当中"p"表示CSS中的标签选择器.$()中的 ...
- 《think in python》学习-4
think in python -4 接口设计: 本章引入了一个实例 来讲解接口方面的知识. 准备工作: 下载swampy模块,从地址下载,并安装,安装信息可以从网页上查看. swampy模块 提供各 ...
- JavaScript引用类型之RegExp类型(正则表达式)
ECMAScript中使用RegExp来支持正则表达式.使用下面类似Perl的语法,就可以创建一个正则表达式. var expression=/pattern/flags; 如上代码: pattern ...
- NHibernate 3.3
今天试了一下NHibernate 3.3比之前的版本简单,只需要引入两个dll,这两个dll分别是:Iesi.Collections.dll和NHibernate.dll 通过 http://nhfo ...
- Http请求头中的字段理解
1.Accept属于请求头, Content-Type属于实体头. Http报头分为通用报头,请求报头,响应报头和实体报头. 请求方的http报头结构:通用报头|请求报头|实体报头 响应方的http报 ...
- C++多文件变量
不要在头文件中定义变量,在头文件中声明变量.定义放在对应的源文件中.其他地方只能用extern声明. 例如: 1 在头文件a.h中声明一个int变量: extern int ix; 2 在源文件a.c ...
- WIN7/8系统下程序接收不到WM_COPYDATA 消息的原因和解决
在WIN7/win8,如果发送消息的程序用户权限低于和接收消息的程序,则消 息无法传递.发送程序必须等于或者等于接收程序的权限.如发送与接收 是同一个用户,或者发送是管理员帐户,接收是是普通用户,这样 ...