ado.net中的多數據表操作淺析—修改
作者:鄭佐??????? 2004-8-5
三、更新數據集
首先需要說明的是我這里去掉了order details表,對兩個表的操作只是其中的幾個字段。下面是窗體界面:
圖3-1
單選框用來選擇不同的更新方法。
在dataaccess類中增加兩個類成員變量:
???? private sqldataadapter _customerdataadapter; //客戶數據適配器
???? private sqldataadapter _orderdataadapter; //訂單數據適配器
?
customerdataadapter在構造函數中的初始化為
//實例化_customerdataadapter
sqlcommand selectcustomercomm = new sqlcommand("getcustomer",_conn);
selectcustomercomm.commandtype = commandtype.storedprocedure;
selectcustomercomm.parameters.add("@customerid",sqldbtype.nchar,5,"customerid");
???????? 
sqlcommand insertcustomercomm = new sqlcommand("addcustomer",_conn);
insertcustomercomm.commandtype = commandtype.storedprocedure;
insertcustomercomm.parameters.add("@customerid",sqldbtype.nchar,5,"customerid");
insertcustomercomm.parameters.add("@companyname",sqldbtype.nvarchar,40,"companyname");
insertcustomercomm.parameters.add("@contactname",sqldbtype.nvarchar,30,"contactname");
?
sqlcommand updatecustomercomm = new sqlcommand("updatecustomer",_conn);
updatecustomercomm.commandtype = commandtype.storedprocedure;
updatecustomercomm.parameters.add("@customerid",sqldbtype.nchar,5,"customerid");
updatecustomercomm.parameters.add("@companyname",sqldbtype.nvarchar,40,"companyname");
updatecustomercomm.parameters.add("@contactname",sqldbtype.nvarchar,30,"contactname");
????????????? 
sqlcommand deletecustomercomm = new sqlcommand("deletecustomer",_conn);
deletecustomercomm.commandtype = commandtype.storedprocedure;
deletecustomercomm.parameters.add("@customerid",sqldbtype.nchar,5,"customerid");
?
_customerdataadapter = new sqldataadapter(selectcustomercomm);
_customerdataadapter.insertcommand = insertcustomercomm;
_customerdataadapter.updatecommand = updatecustomercomm;
_customerdataadapter.deletecommand = deletecustomercomm;
?
上面的代碼完全可以用設計器生成,覺得有些東西自己寫感覺更好,不過代碼還是很多。
對于_orderdataadapter的初始化同上面的差不多,這里我們只看訂單增加的處理,下面是存儲過程:
create procedure? addorder 
(
???? @orderid int out,
???? @customerid nchar(5),
???? @orderdate datetime
)
as
insert into orders
(
???? customerid ,
???? orderdate 
) 
values
(
???? @customerid ,
???? @orderdate
)
--select @orderid = @@identity
set @orderid = scope_identity()
go
?
orderid自動增長值的獲取通過輸出參數來完成,這個相當不錯,如果使用sqldataadapter.rowupdated事件來處理那效率會很低。
對insertordercomm對象的定義為:
sqlcommand insertordercomm = new sqlcommand("addorder",_conn);
insertordercomm.commandtype = commandtype.storedprocedure;
insertordercomm.parameters.add("@orderid",sqldbtype.int,4,"orderid");
insertordercomm.parameters["@orderid"].direction = parameterdirection.output;
insertordercomm.parameters.add("@orderdate",sqldbtype.datetime,8,"orderdate");
insertordercomm.parameters.add("@customerid",sqldbtype.nchar,5,"customerid");
?
在實現數據的更新方法之前我們先來明確一些更新邏輯:
對于標記為刪除的行,先刪除訂單表的數據,再刪除客戶表的數據;
對于標記為添加的行,先添加客戶表的數據,再添加訂單表的數據。
?
(1)實現用獲取修改過的dataset的副本子集來更新數據的方法。
這也是調用xml web service更新數據的常用方法,先來看第一個版本,子集的獲取通過dataset.getchangs方法來完成。
//使用數據集子集更新數據
public void updatecustomerorders(datasetorders ds)
{???????????? 
???? dataset dsmodified = ds.getchanges(datarowstate.modified);//獲取修改過的行
???? dataset dsdeleted = ds.getchanges(datarowstate.deleted);//獲取標記為刪除的行
???? dataset dsadded = ds.getchanges(datarowstate.added);//獲取增加的行
???? try
???? {??? 
???????? _conn.open();//先添加客戶表數據,再添加訂單表數據
???????? if(dsadded != null)
???????? {
????????????? _customerdataadapter.update(dsadded,"customers");
????????????? _orderdataadapter.update(dsadded,"orders");
????????????? ds.merge(dsadded);
???????? }
???????? if(dsmodified != null)//更新數據表
???????? {
???????? ???? _customerdataadapter.update(dsmodified,"customers");
????????????? _orderdataadapter.update(dsmodified,"orders");
????????????? ds.merge(dsmodified);
???????? }
???????? if(dsdeleted != null)//先刪除訂單表數據,再刪除客戶表數據
???????? {
????????????? _orderdataadapter.update(dsdeleted,"orders");
????????????? _customerdataadapter.update(dsdeleted,"customers");
????????????? ds.merge(dsdeleted);
???????? }????????????????? 
???? }
???? catch(exception ex)
???? {
???????? throw new exception("更新數據出錯",ex);
???? }
???? finally
???? {
???????? if(_conn.state != connectionstate.closed)
????????????? _conn.close();
???? }
}
上面的方法看上去比較清晰,不過效率不會很高,至少中間創建了三個dataset,然后又進行了多次合并。
(2)另一方法就是引用更新,不創建副本。
相對來說性能會高許多,但是如果用在web服務上傳輸的數據量會更大(可以結合兩個方法進行改進)。具體的實現就是通過datatable.select方法選擇行狀態來實現。
//引用方式更新數據
public void updatecustomerorders(dataset ds)
{
???? try
???? {??? 
???????? _conn.open(); 
???????? //先添加客戶表數據,再添加訂單表數據 ???? _customerdataadapter.update(ds.tables["customers"].select("","",dataviewrowstate.added));
???? _orderdataadapter.update(ds.tables["orders"].select("","",dataviewrowstate.added));
???? //更新數據表
???? _customerdataadapter.update(ds.tables["customers"].select("","",dataviewrowstate.modifiedcurrent));
???? _orderdataadapter.update(ds.tables["orders"].select("","",dataviewrowstate.modifiedcurrent));
//先刪除訂單表數據,再刪除客戶表數據
???? _orderdataadapter.update(ds.tables["orders"].select("","",dataviewrowstate.deleted));
???? _customerdataadapter.update(ds.tables["customers"].select("","",dataviewrowstate.deleted));??????????? 
???? }
???? catch(exception ex)
???? {
???????? throw new exception("更新數據出錯",ex);
???? }
???? finally
???? {
???????? if(_conn.state != connectionstate.closed)
????????????? _conn.close();
???? }
}
結合上面的兩個方法我們可想到調用web service有更合理的方法來完成。
(3)使用事務
public void updatecustomerorderswithtransaction(dataset ds)
{
???? sqltransaction trans = null;
???? try
???? {??? 
???????? _conn.open();
???????? trans = _conn.begintransaction();
???????? _customerdataadapter.deletecommand.transaction = trans;
???????? _customerdataadapter.insertcommand.transaction = trans;
???????? _customerdataadapter.updatecommand.transaction = trans;
???????? _orderdataadapter.deletecommand.transaction = trans;
???????? _orderdataadapter.insertcommand.transaction = trans;
???????? _orderdataadapter.updatecommand.transaction = trans;
???? _customerdataadapter.update(ds.tables["customers"].select("","",dataviewrowstate.added));
?????????????????? _orderdataadapter.update(ds.tables["orders"].select("","",dataviewrowstate.added));
???? _customerdataadapter.update(ds.tables["customers"].select("","",dataviewrowstate.modifiedcurrent));
???? _orderdataadapter.update(ds.tables["orders"].select("","",dataviewrowstate.modifiedcurrent));
???? _orderdataadapter.update(ds.tables["orders"].select("","",dataviewrowstate.deleted));
???? _customerdataadapter.update(ds.tables["customers"].select("","",dataviewrowstate.deleted));? 
???? ???? trans.commit();
???? }
???? catch(exception ex)
???? {
???????? trans.rollback();
???????? throw new exception("更新數據出錯",ex);
???? }
???? finally
???? {
???????? if(_conn.state != connectionstate.closed)
????????????? _conn.close();
???? }
}
最后讓我們來看看窗體的按鈕更新事件的代碼:
private void buttonupdate_click(object sender, system.eventargs e)
{
????????????? //提交編輯數據
???? this.bindingcontext[this._ds].endcurrentedit();
???? 
???? if(radiobuttonref.checked == true)//引用方式更新
???????? _dataaccess.updatecustomerorders((dataset)_ds);
???? else if(radiobuttontrans.checked == true)//啟用事務更新數據表
???????? _dataaccess.updatecustomerorderswithtransaction((dataset)_ds);
???? else 
???? {
???????? datasetorders changeddata =? (datasetorders)_ds.getchanges();
???????? if(radiobuttonweb.checked == true)//web服務的更正更新
???????? {????????????????????? 
????????????? _dataaccess.updatecustomerorders((dataset)changeddata);
???????? }
???????? else//創建副本合并方式更新
???????? {????????????????? 
????????????? _dataaccess.updatecustomerorders(changeddata);
???????? }
???????? //去除訂單表中添加的虛擬行
???????? foreach(datarow row in _ds.orders.select("","",dataviewrowstate.added))
????????????? _ds.orders.removeordersrow((datasetorders.ordersrow)row);
???????? //去除客戶表中添加的虛擬行
???????? foreach(datarow row in _ds.customers.select("","",dataviewrowstate.added))
????????????? _ds.customers.removecustomersrow((datasetorders.customersrow)row);
???????? _ds.merge(changeddata);
???? }
???? //提交數據集狀態
???? _ds.acceptchanges();
}
?
本文參考:《ado.net core reference》
歡迎交流:(秋楓的blog)http://blog.csdn.net/zhzuo
?
?
?