使用SqlDataAdapter.Update可以方便地對數(shù)據(jù)庫進行快速、批量數(shù)據(jù)更新。我們最常用的多條數(shù)據(jù)更新方法是使用循環(huán)多次執(zhí)行SQL語句或存儲過程,這樣雖然方便,但由于連接和數(shù)據(jù)傳遞要在服務(wù)器和客戶端多次來往,大大增加了整個過程的時間,當(dāng)數(shù)據(jù)越大時越明顯!
下面對SqlDataAdapter.Update作個簡單的演示介紹吧。
測試環(huán)境:SqlServer2008+VS2010+WinXP
1.建立測試數(shù)據(jù)庫和表
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自動生成更新,使用配置數(shù)據(jù)源方式更新,手動編寫命令。
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);
//設(shè)置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,不是為了查詢出數(shù)據(jù),而是要查詢出表結(jié)構(gòu)以向DataTable中填充表結(jié)構(gòu)
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);
//執(zhí)行更新
sda.Update(dt.GetChanges());
//使DataTable保存更新
dt.AcceptChanges();
}
//執(zhí)行后查看表中數(shù)據(jù),如圖:

上面我只作了插入操作,那現(xiàn)在將Select中的Top 0 去掉,把表中的數(shù)據(jù)全部加載到DataTable然后執(zhí)行刪除和更新操作
代碼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);
//設(shè)置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,不是為了查詢出數(shù)據(jù),而是要查詢出表結(jié)構(gòu)以向DataTable中填充表結(jié)構(gòu)
sda.Fill(dt);
//先更新第1,2條數(shù)據(jù)的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條數(shù)據(jù)
dt.Rows.RemoveAt(2);
dt.Rows.RemoveAt(3);
//使用Delete刪除
//dt.Rows[2].Delete();
//dt.Rows[3].Delete();
SqlCommandBuilder scb = new SqlCommandBuilder(sda);
//執(zhí)行更新
sda.Update(dt.GetChanges());
//使DataTable保存更新
dt.AcceptChanges();
}
執(zhí)行后將出錯,錯誤信息“對于不返回任何鍵列信息的 SelectCommand,不支持 UpdateCommand 的動態(tài) SQL 生成。”
出錯原因是建表時沒有設(shè)置主鍵。主鍵唯一標(biāo)識一行數(shù)據(jù),SqlCommandBuilder是根據(jù)DataTable每行的RowState及對應(yīng)的主鍵來生成命令的,沒有主鍵就無法確定刪除哪條數(shù)據(jù),當(dāng)然不可能根據(jù)其他列來刪除,因為其他列可能重復(fù),這樣會刪除多行數(shù)據(jù),很可能執(zhí)行后不是你想要的結(jié)果,這種不確定性的對數(shù)據(jù)的操作方法,微軟當(dāng)然不可能提供給你!
那就給表添加主鍵吧
執(zhí)行如下SQL語句:
alter table student
add constraint PK_Student
primary key(SNo)
再次執(zhí)行上面的代碼2.
執(zhí)行后

我們發(fā)現(xiàn)第1,2行數(shù)據(jù)更新了,但是第3,4行卻沒有刪除。這是怎么回事呢?
先不急,把代碼2中的
dt.Rows.RemoveAt(2);
dt.Rows.RemoveAt(3);
注釋掉,同時把
//dt.Rows[2].Delete();
//dt.Rows[3].Delete();
的注釋去掉,使之執(zhí)行Delete方法而不是RemoveAt方法
再看看結(jié)果:

第3,4行已經(jīng)刪除。
原因是:使用RemoveAt或Remove會將數(shù)據(jù)真正的從DataTable中刪除,而使用Delete則不會,而僅是把當(dāng)前行的RowState值置為deleted.
前面說過SqlCommandBuilder是根據(jù)RowState和主鍵來生成命令的,RemoveAt/Remove把數(shù)據(jù)刪除了,怎么能找到主鍵和RowState呢?
所以使用SqlCommandBuilder時應(yīng)該注意的2點:表要有主鍵,應(yīng)使用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);
//設(shè)置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三個命令添加參數(shù)
SqlParameter paraSNo1, paraSNo2, paraSNo3;//第二個指定參數(shù)值的來源,這里的SNo是指DataTable中的列名
paraSNo1 = new SqlParameter("@SNo", "SNo");
paraSNo2 = new SqlParameter("@SNo", "SNo");
paraSNo3 = new SqlParameter("@SNo", "SNo");
paraSNo1.SourceVersion = DataRowVersion.Current;//指定SourceVersion確定參數(shù)值是列的當(dāng)前值(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條數(shù)據(jù)
dt.Rows.Add(new object[] { 11, "aa11", 31 });
dt.Rows.Add(new object[] { 12, "aa12", 32 });
//先更新第1,2條數(shù)據(jù)的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條數(shù)據(jù)
dt.Rows[2].Delete();
dt.Rows[3].Delete();
SqlCommandBuilder scb = new SqlCommandBuilder(sda);
//執(zhí)行更新
sda.Update(dt.GetChanges());
//使DataTable保存更新
dt.AcceptChanges();
}
執(zhí)行結(jié)果:

可以看到
第SNo為11,12的數(shù)據(jù)是新增的。
原來SNo為1,2的數(shù)據(jù)中SName已經(jīng)從AA,BB更改為CC,DD,另一列SAge從33,44更改為55,66。
原來SNo為5,6也就是第3,4條數(shù)據(jù)已經(jīng)被刪除