透過vs.net數據窗體向導看Ado.net
2024-07-10 13:03:01
供稿:網友
本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。透過vs.net數據窗體向導看ado.net
鄭佐2005-1-1
在csdn上經常碰到有人問一些ado.net的問題,特別是開發信息管理系統之類的跟數據庫比較密切的程序時,在數據和界面層的開發中會遇到不少常見問題,下面我們通過vs.net自帶的數據窗體向導來看看能它能幫我們決絕什么問題。
一.使用向導
新建windows 應用程序,為當前項目添加組件,選擇數據窗體向導,這里名稱填寫為dataform1.cs。單擊打開出現數據窗體向導對話框。創建新的類型化數據集mydataset。使用本地數據連接向導,這里我選擇northwind庫作為數據源。在選擇表或視圖那一步添加categories表和products表。添加一個表之間的關系取名categoryproductrel。在選擇顯示樣式一步中選擇顯示數據的方式為單個控件中的單個記錄,這個就會有數據綁定到文本框。可以用數據導航來選擇父表的記錄。向導完成后會生成一個oledbconnection,幾個表生成幾個oledbdataadapter負責數據的獲取和更新。另外就是一個強類型的數據集。
整個程序的運行界面如下:
基本功能都包括了,不過等你點擊幾下,程序界面上就會出現小的bug,微軟可能也估計到沒有人會要這個窗體來處理數據,不過這個不是我們所關心的。
二.數據填充
先來看看數據集結構:
一個categories表作為父表,products表作為子表,categoryid為外鍵,建立的數據表關系。
通過加載按鈕數據庫中的相關數據會被填充到數據集。執行的loaddataset()方法的過程如下:
使用dataadatpter.fill()方法填充數據到臨時的一個數據集,如果操作成功,將合并這個臨時數據集到原有的數據集,datagrid通過表關系綁定子表。
// 嘗試填充臨時數據集。
this.filldataset(objdatasettemp);
grdproducts.datasource = null;
// 清空數據集中的舊記錄。
objmydataset.clear();
// 將記錄合并到主數據集中。
objmydataset.merge(objdatasettemp);
grdproducts.setdatabinding(objmydataset, "categories.categoryproductrel");
在數據填充的方法中我們注意到
dataset.enforceconstraints = false;
這一步會對數據填充效率會有所提高。
另外還有一個細節就是執行兩個以上dataadapter的數據訪問方法時顯式打開關閉數據連接效率會比較高。因為在執行dataadapter的數據更新方法前和方法后數據連接connection實例的狀態不會改變。如果下面代碼。
//this.oledbconnection1.open();
this.oledbdataadapter1.fill(dataset);
this.oledbdataadapter2.fill(dataset);
執行之前connection的狀態是關閉的,那可想而知這一過程會執行兩次打開連接關閉連接。
其實一次就夠。
為了數據的嚴密性,填充完數據后不要忘了加上下面代碼,
// 重新打開約束檢查。
dataset.enforceconstraints = true;
如果是直讀那就無所謂了。
有了數據填充那就來看數據的單值綁定和多值綁定。
三.數據綁定
數據的單值綁定如下:
this.editcategoryid.databindings.add(new system.windows.forms.binding("text", this.objmydataset, "categories.categoryid"));
this.editcategoryname.databindings.add(new system.windows.forms.binding("text", this.objmydataset, "categories.categoryname"));
上面一段代碼把數據表的列綁定到了textbox的text屬性上。
數據的多值綁定如下:
grdproducts.setdatabinding(objmydataset, "categories.categoryproductrel");
可見通過關系綁定數據相當方便。
四.數據瀏覽
這里通過bindingcontext對象的索引得到bindingmanagerbase實例,而bindingmanagerbase.position就是我們需要的,通過position來顯示某一行的數據記錄。
例如下一條:
this.bindingcontext[objmydataset,"categories"].position = (this.bindingcontext[objmydataset,"categories"].position + 1);
最后一條:
this.bindingcontext[objmydataset,"categories"].position = (this.objmydataset.tables["categories"].rows.count - 1);
另外調用positionchanged()方法來改變導航按鈕之間的索引顯示。
五.數據編輯
從添加方法中我們可以看到下面代碼:
// 清除當前編輯內容
this.bindingcontext[objmydataset,"categories"].endcurrentedit();
經常有人在csdn上提問為什么在編輯datagrid或textbox的時候,只有當編輯框失去焦點的時候才會被保存。要實現不改變焦點就保存可以通過上面代碼實現。
相對應的取消如下:
this.bindingcontext[objmydataset,"categories"].cancelcurrentedit();
刪除數據的代碼如下:
this.bindingcontext[objmydataset,"categories"].removeat(this.bindingcontext[objmydataset,"categories"].position);
看到上面代碼發現原來數據不是真正的在數據源刪除,不過我們開發的時候可能用的更多的是datarow的delete()方法,這樣能夠提交數據更新到數據源。
六.數據更新
向導生成的代碼如下:
public void updatedataset()
{
// 創建一個新數據集來保存對主數據集所做的更改。
windowsapplication1.mydataset objdatasetchanges = new windowsapplication1.mydataset();
// 停止當前的任何編輯。
this.bindingcontext[objmydataset,"categories"].endcurrentedit();
this.bindingcontext[objmydataset,"products"].endcurrentedit();
// 獲取對主數據集所做的更改。
objdatasetchanges = ((windowsapplication1.mydataset)(objmydataset.getchanges()));
// 檢查是否做了任何更改。
if ((objdatasetchanges != null))
{
try
{
// 需要做一些更改,所以嘗試通過調用 update 方法
// 和傳遞數據集以及任何參數來更新數據源。
this.updatedatasource(objdatasetchanges);
objmydataset.merge(objdatasetchanges);
objmydataset.acceptchanges();
}
catch (system.exception eupdate)
{
// 在此處添加錯誤處理代碼。
throw eupdate;
}
// 添加代碼以檢查返回的數據集中是否有任何可能已被
// 推入到行對象錯誤中的錯誤。
}
}
更新過程很經典,通過獲取修改過的數據集更新子集提交到數據源完成更新動作,接著合并子集到原有數據集,順便提一下,合并的過程是基于數據表主鍵來判斷的。通過調用dataset.acceptchanges()方法提交自加載此 dataset 或上次調用 acceptchanges 以來對 dataset 進行的所有更改。對應的就是data.rejectchanges();回滾自創建 dataset 以來或上次調用 dataset.acceptchanges 以來對 dataset 進行的所有更改。
七.補充
對于數據的更新需要視程序環境而定,不能都通過獲取子集再合并的方法,具體請看ado.net中的多數據表操作淺析—修改一文。也有人問起怎樣實現這樣的功能:在數據庫中的某一個字段數據為0或1,而在程序顯示上想讓它顯示為是或否,這里我認為最好不要在sql語句上做文章,代替的方法就是使用binding對象的format 事件和parse事件。binding.format 事件,當將某控件的屬性綁定到某個數據值時發生。binding.parse 事件,在數據綁定控件的值更改時發生。還有可以通過bindingmanagerbase.positionchanged事件來設置各個按鈕的狀態。需要具體的例子可以看msdn或《ado.net core reference》一書。另外,使用try{}catch (system.exception ex){}還是要視情況而定,不能一味的全都通過exception基類把什么都撲捉了,如果知道有可能會拋出什么類型的異常,還是越具體越好,造成的反面效果就是要寫更多的代碼。具體為什么要這么做可以看《applied microsoft.net framework programming》一書。