作者:鄭佐 2005-1-1
在 csdn 上經常碰到有人問一些 Ado.net 的問題,特別是開發信息管理系統之類的跟數據庫比較密切的程序時,在數據和界面層的開發中會遇到不少常見問題,下面我們通過 vs.net 自帶的數據窗體向導來看看能它能幫我們決絕什么問題。
一.使用向導
新建 Windows 應用程序,為當前項目添加組件,選擇數據窗體向導,這里名稱填寫為 DataForm1.cs 。單擊打開出現數據窗體向導對話框。創建新的類型化數據集 MyDataSet 。使用本地數據連接向導,這里我選擇 Northwind 庫作為數據源。在選擇表或視圖那一步添加 Categories 表和 Products 表。添加一個表之間的關系取名 CategoryProductRel 。在選擇顯示樣式一步中選擇顯示數據的方式為單個控件中的單個記錄,這個就會有數據綁定到文本框。可以用數據導航來選擇父表的記錄。向導完成后會生成一個 OleDbConnection ,幾個表生成幾個 OleDbDataAdapter 負責數據的獲取和更新。另外就是一個強類型的數據集。
整個程序的運行界面如下:
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"></shapetype><stroke joinstyle="miter"></stroke><formulas></formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f><lock aspectratio="t" v:ext="edit"></lock>
基本功能都包括了,不過等你點擊幾下,程序界面上就會出現小的
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
》一書。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
