吳昌錢
?
關(guān)于ADO.NET數(shù)據(jù)訪問方式編程的研究
吳昌錢
華僑大學(xué)計(jì)算機(jī)學(xué)院
該文研究兩個(gè)方面的內(nèi)容:(1)研究ADO.NET模型,對各組成部分作分析。(2)具體分析在不同數(shù)據(jù)訪問情況下,如何選擇ADO.NET中的組件來編程實(shí)現(xiàn)對數(shù)據(jù)訪問操作。其中,理解ADO.NET模型中各組件的實(shí)質(zhì)尤為重要。只有充分理解ADO.NET模型,才能確保在針對不同的數(shù)據(jù)訪問情形下不會選錯(cuò)ADO.NET組件,或選擇最適合的組件編寫出高效率的代碼。
ADO.NET模型 ADO.NET組件 ADO.NET數(shù)據(jù)訪問
NET Framework類庫中包含的一整套數(shù)據(jù)訪問技術(shù),用于提供對關(guān)系數(shù)據(jù)和XML的訪問,這就是ADO.NET。ADO.NET是Microsoft為大型分布式環(huán)境設(shè)計(jì)而引入,是基于原來ADO提出的全新的、更靈活的新技術(shù),適用于.NET應(yīng)用程序各種數(shù)據(jù)的存儲。它支持XML編程模型,采用XML作為數(shù)據(jù)交換格式,因而可以非常順利地通過防火墻,任何遵循此標(biāo)準(zhǔn)的程序都可以用它進(jìn)行數(shù)據(jù)處理和通信,與操作系統(tǒng)平臺無關(guān),與語言也無關(guān)。
圖1 ADO.NET模型的簡要模型
圖1為ADO.NET模型的簡要模型,關(guān)于DataSet對XML文件的操作,圖中并沒有列出,這里重點(diǎn)體現(xiàn)的是ADO.NET如何從后臺服務(wù)器的數(shù)據(jù)庫中獲得數(shù)據(jù),實(shí)現(xiàn)對數(shù)據(jù)的操作。
1.1.1物理層數(shù)據(jù)庫。保存在物理設(shè)備(如硬盤)中數(shù)據(jù),主要是關(guān)系型數(shù)據(jù)庫,這些數(shù)據(jù)由后臺數(shù)據(jù)庫服務(wù)器維護(hù)。
1.1.2數(shù)據(jù)提供程序。它實(shí)現(xiàn)將物理數(shù)據(jù)到邏輯數(shù)據(jù)的轉(zhuǎn)化。
1.1.3數(shù)據(jù)集。即邏輯數(shù)據(jù),是物理數(shù)據(jù)庫在本地的一個(gè)副本,數(shù)據(jù)以XML的形式存儲位于內(nèi)存中,由表、視圖等對象構(gòu)成。
1.1.4數(shù)據(jù)使用程序(應(yīng)用程序界面)。主要指Windows應(yīng)用程序的form窗體界面或web應(yīng)用程序的網(wǎng)頁界面,屬于前臺應(yīng)用程序部分。
實(shí)現(xiàn)前臺應(yīng)用程序?qū)笈_物理數(shù)據(jù)庫的定位,必須包括對數(shù)據(jù)庫服務(wù)器名后IP的定位信息,以及對數(shù)據(jù)庫的定位信息。即先找到服務(wù)器,再找到數(shù)據(jù)庫。此外,還包括provider(提供者)、登錄方式等信息。
ADO.NET提供了兩種數(shù)據(jù)訪問的模式。即Connection在客戶端使用數(shù)據(jù)時(shí),Connection與數(shù)據(jù)庫服務(wù)器是否處于連著的狀態(tài)區(qū)分為兩種訪問模式。一種為連接模式(Connected),另一種為非連接模式(Disconnected)。過去ADO技術(shù)只支持連接模式,相比于傳統(tǒng)的數(shù)據(jù)庫訪問模式,非連接的模式為我們提供了更大的可升級性和靈活性。ADO.NET支持連接模式和非連接模式下的數(shù)據(jù)庫訪問,但ADO.NET主要是為了在非連接的環(huán)境中連接數(shù)據(jù)而特別設(shè)計(jì)的。在非連接模式下,使用的是應(yīng)用程序服務(wù)器內(nèi)存中的邏輯數(shù)據(jù)庫,即DataSet中的數(shù)據(jù)。如果沒有邏輯數(shù)據(jù)庫(不使用DataSet)也就不能實(shí)現(xiàn)非連接情況下數(shù)據(jù)訪問,即對于使用DataReader就只能是ADO.NET的連接模式數(shù)據(jù)訪問。
此外,ADO.NET對于采取連接和非連接數(shù)據(jù)訪問,對Connection連接組件與數(shù)據(jù)庫服務(wù)器的連接與斷開控制操作不同。在連接模式的環(huán)境下,Connection的通/斷由ADO.NET自動(dòng)控制,這可使用以下語句獲得驗(yàn)證:
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)”的結(jié)果為輸出了Closed,且Gridview1中顯示了表的數(shù)據(jù),這說明“語句(2)”執(zhí)行成功,完成了物理數(shù)據(jù)到內(nèi)存邏輯數(shù)據(jù)的轉(zhuǎn)化。即執(zhí)行“語句(2)”時(shí),ADO.NET自動(dòng)控制了Connection組件的通/斷。對于ADO.NET的連接模式就地使用以下代碼進(jìn)行數(shù)據(jù)訪問了,要顯示地控制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)有關(guān),即指明操作的命令語句,實(shí)現(xiàn)物理數(shù)據(jù)到邏輯數(shù)據(jù)的轉(zhuǎn)化。
DataAdapter組件的名稱叫作適配器組件,這也能夠明確它的功能,即實(shí)現(xiàn)物理數(shù)據(jù)到邏輯數(shù)據(jù)的映射轉(zhuǎn)化。所以在采用DataAdapter組件時(shí)可以不使用Command組件。其實(shí),DataAdapter組件是一種復(fù)合型組件,它包含4個(gè)具體的Command,即SelectCommand、UpdateCommand、DelectCommand、InsertCommand。
DataSet與DataReader存在以下異同。
1.4.1相同點(diǎn)。DataSet與DataReader中的數(shù)據(jù)同處內(nèi)存中,同樣是存放記錄的邏輯形式數(shù)據(jù)。
1.4.2不同點(diǎn)
(1)他們的執(zhí)行數(shù)據(jù)處理的復(fù)合不同。前者存放的是DataTable形式的若干條記錄數(shù)據(jù),后者在某個(gè)時(shí)刻內(nèi)存中每次只存一條記錄。DataReader是屬于低開銷的對象。
(2)它們的工作原理不同。前者為集合數(shù)據(jù)操作,后者為流式數(shù)據(jù)操作。前者存放的邏輯數(shù)據(jù),可以以整張表的形式進(jìn)行操作,這點(diǎn)從他們的英文名稱就能了解到,“SET”為集合型操作。后者在某個(gè)時(shí)刻內(nèi)存中每次只存一條記錄,即使是一條記錄,它也是按字段逐個(gè)讀取。SELECT 命令獲取查詢的數(shù)據(jù), 通過DataReader 對象的屬性和方法, 將獲取的數(shù)據(jù)以只讀方式從當(dāng)前的數(shù)據(jù)記錄順向逐條處理, DataReader對象相當(dāng)于是只讀/只向前移的游標(biāo),讀取規(guī)則類似于象棋中兵的走法,每次只能向前一步,不得向后。所以對于編程時(shí),需要注意,Datareader應(yīng)使用以下形式的語句結(jié)構(gòu)進(jìn)行數(shù)據(jù)讀取操作:
while (dr.Read()) //dr為DataReader對象
{行數(shù)據(jù)操作}
(3)它們與數(shù)據(jù)庫服務(wù)器的連接狀態(tài)不同,即數(shù)據(jù)訪問的模式不同。DataSet使用連接模式(Connected),DataReader使用非連接模式(Disconnected)。這點(diǎn)可以想象,基于DataReader每次只存放一條記錄,如果是要讀取執(zhí)行select語句后返回的多條記錄,DataReader使用的連接組件與數(shù)據(jù)庫服務(wù)器以頻繁的“斷開/連接”方式實(shí)現(xiàn)對多條記錄的操作是不可取的。
(4)它們對數(shù)據(jù)的操作能力不一樣。前者能對數(shù)據(jù)進(jìn)行查詢和更新操作。后者只能以read(即查詢)的方式操作數(shù)據(jù),這點(diǎn)從他們的英文名稱就能了解到,是“dataReader”,并非“DataWriter”。
(5)它們讀取數(shù)據(jù)的速度不同。DataSet與DataReader 的復(fù)合不同,決定了他們的讀取速度不同,在只對數(shù)據(jù)進(jìn)行讀取時(shí),建議使用DataReader。
下面以ADO.NET模型中組件的關(guān)聯(lián)關(guān)系,給出數(shù)據(jù)的訪問路徑。明確這些數(shù)據(jù)訪問路徑,對于提高ADO.NET編程效率有很好的幫助。保證能夠在訪問不同形式數(shù)據(jù)時(shí)選擇正確的ADO.NET組件。
2.1.1讀取
(1)數(shù)據(jù)庫——>Connection——>DataAdapter——>Dataset——>界面
(2)數(shù)據(jù)庫——>Connection——>Command(賦予select語句)——>DataAdapter——>Dataset——>界面
(3)數(shù)據(jù)庫——>Connection——>DataAdapter對象.SelectCommand——>Dataset——>界面
以上三個(gè)讀取數(shù)據(jù)的組件使用方式,適合于以集合操作的方式讀取多條記錄或單條記錄數(shù)據(jù)。數(shù)據(jù)感知組件可以是列感知組件,如DataList、DropDownList等,也可以其他的數(shù)據(jù)感知組件,如Datagrid、GridView、Repeater等。
2.1.2更新
(1)DataAdapater對象. Update(需要更新的對象)
對于以上三種讀取的數(shù)據(jù),在進(jìn)行更新回?cái)?shù)據(jù)庫服務(wù)器時(shí),如果直接使用DataAdapter對象的Update方法時(shí),程序會出現(xiàn)異常。由于以上三種讀取的數(shù)據(jù)在以編程的方式創(chuàng)建DataAdapter時(shí)只設(shè)置了SelectCommand屬性,沒有設(shè)置UpdateCommand,DeleteCommand和InsertCommand這三個(gè)命令屬性,ADO.NET并不會根據(jù)所提供的SelectCommand對象,創(chuàng)建其他具有更新功能的Command組件。這不同于使用可視化方式創(chuàng)建ADO.NET對象。如果是可視化方式操作的,在指定Select語句的情況下,更新功能的Command組件可以由ADO.NET連接向?qū)ё詣?dòng)生成。為此,我們需要?jiǎng)?chuàng)建一個(gè)CommandBuilder對象為表的更新自動(dòng)生成SQL語句。語法如下:
CommandBuilder commandbuild對象=New Command
Builder(DataAdapater對象);
以下示例完成數(shù)據(jù)的讀取,并采用DataAdapater對象完成數(shù)據(jù)的更新,代碼如下:
SqlConnection conn ; SqlDataAdapter da;
DataSet ds ,dsChange; // dsChange用于獲取用戶作更新的數(shù)據(jù)
private void Page_Load(object sender, System.EventArgs e)//讀取數(shù)據(jù)
{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)//更新數(shù)據(jù)
{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——>數(shù)據(jù)庫
此方式為直接使用Command對象將客戶端數(shù)據(jù)更新回物理數(shù)據(jù)庫。以下繼續(xù)上述示例,采用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()+"條");
//以下代碼實(shí)現(xiàn)刷新數(shù)據(jù)
ds.Tables["Tb_Customers"].Clear();
da.Fill(ds, "Tb_Customers");
Page.DataBind();
}
}
對于以上兩種更新數(shù)據(jù)的方法,適用的環(huán)境有所區(qū)別。在前端應(yīng)用程序的數(shù)據(jù)感知組件為可編輯情況下,采用前種方式,可以實(shí)現(xiàn)將數(shù)據(jù)感知組中對數(shù)據(jù)的多個(gè)修改一次性保存回物理數(shù)據(jù)庫服務(wù)器。如在DataGrid或GridView中對多條記錄數(shù)據(jù)進(jìn)行編輯,而后提交保存。如果是單條記錄的更新,則可以選用后種更新方式。
讀?。簲?shù)據(jù)庫——>Connection——>Command——>DataReader——>界面
適合于以流式操作的方式讀取多條記錄或單條記錄數(shù)據(jù)。數(shù)據(jù)感知組件與采用集合操作方式時(shí)使用的組件相同。但是采用流式讀取操作數(shù)據(jù),主要是為了數(shù)據(jù)的讀取。ADO.NET并不提供流式寫入數(shù)據(jù)。雖然在理論上,對于數(shù)據(jù)保存回?cái)?shù)據(jù)庫服務(wù)器是可行的,但是沒有必要,因?yàn)槿绻氡蛔x到客戶端的數(shù)據(jù)能被更新回后臺數(shù)據(jù)庫服務(wù)器,采用集合的操作方式就足以完成了。此外,對于采用流式數(shù)據(jù)寫回后臺數(shù)據(jù)集庫服務(wù)器,這在技術(shù)上的確也是比較麻煩的。但是在以流式操作的方式讀取的是單一記錄的數(shù)據(jù),如果需要保存還是可以考慮上面提到的“界面——>Command對象——>Connection——>數(shù)據(jù)庫”這一更新數(shù)據(jù)方式,效率也不低。
從ADO.NET模型和ADO.NET數(shù)據(jù)訪問組件的選用兩個(gè)方面對ADO.NET進(jìn)行了編程層次上的研究,明確這兩個(gè)方面對于使用ADO.NET進(jìn)行數(shù)據(jù)訪問編程,提高編程效率有一定的幫助。
[1] 微軟公司. 面向.NET的Web應(yīng)用程序設(shè)計(jì)[M].北京:高等教育出版社,2004.
[2] [美]Shawn Wildermuth.周靖,譯. ADO.NET實(shí)用指南——面向Internet世界的數(shù)據(jù)訪問技術(shù)[M].北京: 清華大學(xué)出版社,2003.