吳昌錢
?
關于ADO.NET數據訪問方式編程的研究
吳昌錢
華僑大學計算機學院
該文研究兩個方面的內容:(1)研究ADO.NET模型,對各組成部分作分析。(2)具體分析在不同數據訪問情況下,如何選擇ADO.NET中的組件來編程實現對數據訪問操作。其中,理解ADO.NET模型中各組件的實質尤為重要。只有充分理解ADO.NET模型,才能確保在針對不同的數據訪問情形下不會選錯ADO.NET組件,或選擇最適合的組件編寫出高效率的代碼。
ADO.NET模型 ADO.NET組件 ADO.NET數據訪問
NET Framework類庫中包含的一整套數據訪問技術,用于提供對關系數據和XML的訪問,這就是ADO.NET。ADO.NET是Microsoft為大型分布式環境設計而引入,是基于原來ADO提出的全新的、更靈活的新技術,適用于.NET應用程序各種數據的存儲。它支持XML編程模型,采用XML作為數據交換格式,因而可以非常順利地通過防火墻,任何遵循此標準的程序都可以用它進行數據處理和通信,與操作系統平臺無關,與語言也無關。

圖1 ADO.NET模型的簡要模型
圖1為ADO.NET模型的簡要模型,關于DataSet對XML文件的操作,圖中并沒有列出,這里重點體現的是ADO.NET如何從后臺服務器的數據庫中獲得數據,實現對數據的操作。
1.1.1物理層數據庫。保存在物理設備(如硬盤)中數據,主要是關系型數據庫,這些數據由后臺數據庫服務器維護。
1.1.2數據提供程序。它實現將物理數據到邏輯數據的轉化。
1.1.3數據集。即邏輯數據,是物理數據庫在本地的一個副本,數據以XML的形式存儲位于內存中,由表、視圖等對象構成。
1.1.4數據使用程序(應用程序界面)。主要指Windows應用程序的form窗體界面或web應用程序的網頁界面,屬于前臺應用程序部分。
實現前臺應用程序對后臺物理數據庫的定位,必須包括對數據庫服務器名后IP的定位信息,以及對數據庫的定位信息。即先找到服務器,再找到數據庫。此外,還包括provider(提供者)、登錄方式等信息。
ADO.NET提供了兩種數據訪問的模式。即Connection在客戶端使用數據時,Connection與數據庫服務器是否處于連著的狀態區分為兩種訪問模式。一種為連接模式(Connected),另一種為非連接模式(Disconnected)。過去ADO技術只支持連接模式,相比于傳統的數據庫訪問模式,非連接的模式為我們提供了更大的可升級性和靈活性。ADO.NET支持連接模式和非連接模式下的數據庫訪問,但ADO.NET主要是為了在非連接的環境中連接數據而特別設計的。在非連接模式下,使用的是應用程序服務器內存中的邏輯數據庫,即DataSet中的數據。如果沒有邏輯數據庫(不使用DataSet)也就不能實現非連接情況下數據訪問,即對于使用DataReader就只能是ADO.NET的連接模式數據訪問。
此外,ADO.NET對于采取連接和非連接數據訪問,對Connection連接組件與數據庫服務器的連接與斷開控制操作不同。在連接模式的環境下,Connection的通/斷由ADO.NET自動控制,這可使用以下語句獲得驗證:
protected void Page_Load(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(連接字符串);
SqlDataAdapter da = new SqlDataAdapter("select * from products",conn);
DataSet ds = new DataSet();
Response.Write(conn.State.ToString());//語句(1)
da.Fill(ds);// 語句(2)
Response.Write(conn.State.ToString());//語句(3)
GridView1.DataSource = ds;
GridView1.DataBind();
}
以上,“語句(1)”、“語句(3)”的結果為輸出了Closed,且Gridview1中顯示了表的數據,這說明“語句(2)”執行成功,完成了物理數據到內存邏輯數據的轉化。即執行“語句(2)”時,ADO.NET自動控制了Connection組件的通/斷。對于ADO.NET的連接模式就地使用以下代碼進行數據訪問了,要顯示地控制Connection組件的通/斷。
SqlConnection conn = new SqlConnection(連接字符串);
SqlCommand cmdAuthors = new SqlCommand("select * from products",conn);
try
{ conn.Open();
SqlDataReader dr= cmdAuthors.ExecuteReader();
GridView1.DataSource=dr;
GridView1.DataBind();
}
finally
{ conn.Close(); }
Command組件的名為命令組件,這也就意味著它的功能與4種命令(Select、Update、Delect、Insert)有關,即指明操作的命令語句,實現物理數據到邏輯數據的轉化。
DataAdapter組件的名稱叫作適配器組件,這也能夠明確它的功能,即實現物理數據到邏輯數據的映射轉化。所以在采用DataAdapter組件時可以不使用Command組件。其實,DataAdapter組件是一種復合型組件,它包含4個具體的Command,即SelectCommand、UpdateCommand、DelectCommand、InsertCommand。
DataSet與DataReader存在以下異同。
1.4.1相同點。DataSet與DataReader中的數據同處內存中,同樣是存放記錄的邏輯形式數據。
1.4.2不同點
(1)他們的執行數據處理的復合不同。前者存放的是DataTable形式的若干條記錄數據,后者在某個時刻內存中每次只存一條記錄。DataReader是屬于低開銷的對象。
(2)它們的工作原理不同。前者為集合數據操作,后者為流式數據操作。前者存放的邏輯數據,可以以整張表的形式進行操作,這點從他們的英文名稱就能了解到,“SET”為集合型操作。后者在某個時刻內存中每次只存一條記錄,即使是一條記錄,它也是按字段逐個讀取。SELECT 命令獲取查詢的數據, 通過DataReader 對象的屬性和方法, 將獲取的數據以只讀方式從當前的數據記錄順向逐條處理, DataReader對象相當于是只讀/只向前移的游標,讀取規則類似于象棋中兵的走法,每次只能向前一步,不得向后。所以對于編程時,需要注意,Datareader應使用以下形式的語句結構進行數據讀取操作:
while (dr.Read()) //dr為DataReader對象
{行數據操作}
(3)它們與數據庫服務器的連接狀態不同,即數據訪問的模式不同。DataSet使用連接模式(Connected),DataReader使用非連接模式(Disconnected)。這點可以想象,基于DataReader每次只存放一條記錄,如果是要讀取執行select語句后返回的多條記錄,DataReader使用的連接組件與數據庫服務器以頻繁的“斷開/連接”方式實現對多條記錄的操作是不可取的。
(4)它們對數據的操作能力不一樣。前者能對數據進行查詢和更新操作。后者只能以read(即查詢)的方式操作數據,這點從他們的英文名稱就能了解到,是“dataReader”,并非“DataWriter”。
(5)它們讀取數據的速度不同。DataSet與DataReader 的復合不同,決定了他們的讀取速度不同,在只對數據進行讀取時,建議使用DataReader。
下面以ADO.NET模型中組件的關聯關系,給出數據的訪問路徑。明確這些數據訪問路徑,對于提高ADO.NET編程效率有很好的幫助。保證能夠在訪問不同形式數據時選擇正確的ADO.NET組件。
2.1.1讀取
(1)數據庫——>Connection——>DataAdapter——>Dataset——>界面
(2)數據庫——>Connection——>Command(賦予select語句)——>DataAdapter——>Dataset——>界面
(3)數據庫——>Connection——>DataAdapter對象.SelectCommand——>Dataset——>界面
以上三個讀取數據的組件使用方式,適合于以集合操作的方式讀取多條記錄或單條記錄數據。數據感知組件可以是列感知組件,如DataList、DropDownList等,也可以其他的數據感知組件,如Datagrid、GridView、Repeater等。
2.1.2更新
(1)DataAdapater對象. Update(需要更新的對象)
對于以上三種讀取的數據,在進行更新回數據庫服務器時,如果直接使用DataAdapter對象的Update方法時,程序會出現異常。由于以上三種讀取的數據在以編程的方式創建DataAdapter時只設置了SelectCommand屬性,沒有設置UpdateCommand,DeleteCommand和InsertCommand這三個命令屬性,ADO.NET并不會根據所提供的SelectCommand對象,創建其他具有更新功能的Command組件。這不同于使用可視化方式創建ADO.NET對象。如果是可視化方式操作的,在指定Select語句的情況下,更新功能的Command組件可以由ADO.NET連接向導自動生成。為此,我們需要創建一個CommandBuilder對象為表的更新自動生成SQL語句。語法如下:
CommandBuilder commandbuild對象=New Command
Builder(DataAdapater對象);
以下示例完成數據的讀取,并采用DataAdapater對象完成數據的更新,代碼如下:
SqlConnection conn ; SqlDataAdapter da;
DataSet ds ,dsChange; // dsChange用于獲取用戶作更新的數據
private void Page_Load(object sender, System.EventArgs e)//讀取數據
{conn = new SqlConnection(連接字符串);
da = new SqlDataAdapter("select * from Customers", conn);
ds = new DataSet();
dsChange = new DataSet();
da.Fill(ds,"Tb_Customers");
DataGrid1.DataSource = ds;
DataGrid1.DataBind();
}
private void Btn1_Click(object sender,System.EventArgs e)//更新數據
{dsChange=ds.GetChanges();
if(dsChange!=null)
{try
{SqlCommandBuilder CB =new SqlCommandBuilder(da);
da.Update(ds.Tables["Tb_Customers"]);
ds.Tables["Tb_Customers"].Clear();
da.Fill(ds," Tb_Customers");
Response.Write(ds.Tables["Tb_Customers"].TableName );
Page.DataBind();
Response.Write("成功修改記錄"
+dsChange.Tables["Tb_Customers"].Rows.Count.ToString()+"條");
}
catch (System.Exception err)
{Response.Write(err.Message); }
}
}
(2)界面——>Command對象——>Connection——>數據庫
此方式為直接使用Command對象將客戶端數據更新回物理數據庫。以下繼續上述示例,采用Command對象完成刪除記錄功能。代碼如下:
private void Btn2_Click(object sender,System.EventArgs e)//刪除記錄
{int effect_Line=0;
SqlCommand cm=new SqlCommand("Delete from Customers where CustomerID='10249' ",conn);
conn.Open();
effect_Line=cm.ExecuteNonQuery();
conn.Close();
if (effect_Line>0)
{Response.Write("成功刪除記錄"+effect_Line.ToString()+"條");
//以下代碼實現刷新數據
ds.Tables["Tb_Customers"].Clear();
da.Fill(ds, "Tb_Customers");
Page.DataBind();
}
}
對于以上兩種更新數據的方法,適用的環境有所區別。在前端應用程序的數據感知組件為可編輯情況下,采用前種方式,可以實現將數據感知組中對數據的多個修改一次性保存回物理數據庫服務器。如在DataGrid或GridView中對多條記錄數據進行編輯,而后提交保存。如果是單條記錄的更新,則可以選用后種更新方式。
讀取:數據庫——>Connection——>Command——>DataReader——>界面
適合于以流式操作的方式讀取多條記錄或單條記錄數據。數據感知組件與采用集合操作方式時使用的組件相同。但是采用流式讀取操作數據,主要是為了數據的讀取。ADO.NET并不提供流式寫入數據。雖然在理論上,對于數據保存回數據庫服務器是可行的,但是沒有必要,因為如果想被讀到客戶端的數據能被更新回后臺數據庫服務器,采用集合的操作方式就足以完成了。此外,對于采用流式數據寫回后臺數據集庫服務器,這在技術上的確也是比較麻煩的。但是在以流式操作的方式讀取的是單一記錄的數據,如果需要保存還是可以考慮上面提到的“界面——>Command對象——>Connection——>數據庫”這一更新數據方式,效率也不低。
從ADO.NET模型和ADO.NET數據訪問組件的選用兩個方面對ADO.NET進行了編程層次上的研究,明確這兩個方面對于使用ADO.NET進行數據訪問編程,提高編程效率有一定的幫助。
[1] 微軟公司. 面向.NET的Web應用程序設計[M].北京:高等教育出版社,2004.
[2] [美]Shawn Wildermuth.周靖,譯. ADO.NET實用指南——面向Internet世界的數據訪問技術[M].北京: 清華大學出版社,2003.