以往我們對數據庫進行操作的方法是先連接上一個數據庫,在保持連接的狀態下進行數據的各種操作,如增刪改查。這樣的狀況會有兩個弊病,一是始終保持連接會造成資源的浪費,二是網絡的各種不穩定因素會是這種連接發生丟失,從而對數據的操作也將丟失。
鑒於以上所說道的兩個或更多的其他原因,微軟提出了另一種操作模式,就是非連接模式的數據操作,當然也沒有丟棄以前ado中那種典型的連接模式的數據操作,故而誕生了ado.net及其兩種典型的數據操作模式,即連接模式和非連接模式。
當然,無論是采用那種模式來操作數據,首先是要取得數據連接然後對數據源進行操作或對數據源的副本進行操作。則連接為第一步必須完成的工作。連接的方法和ado時代沒有多大的差別,不外乎與首先建立一個連接對象(或叫做實例化一個連接對象),要完成連接必須知道連接的數據源地址,有的還要知道數據源提供者。下面是典型的列子:
string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
string connstring="Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=Northwind;";
//一般來說OLEDB數據源需要設定provider
一次到位的實例化連接對象
OleDbConnection myconn=new OleDbConnection(connstring);
或用Connection的屬性設置連接對象的數據源
OleDbConnection myconn=new OleDbConnection();
myconn.ConnectionString=connstring;
接下來就可用connection的open()方法打開連接了
myconn.open()
連接已經完成,接下來進入最重要的數據操作階段(需要詳細了解連接對象建立的同學可以自己去多查查資料哦)
一、連接模式
連接模式下 擔負主要責任的對象是DataReader(然而說到DataReader那又不得不提到ExcuteReader()這個方法,因為DataReader是沒有構造函數的一個類,DataReader只能通過command類的excutereader()方法來實例化),所以Datareader有以下幾個特點:
1.它無構造函數只能通過command的excutereader()方法來實例化,
如:sqlcommand sqlcm=new sqlcommand(); sqldatarader dr =sqlcm.excutereader();
2.它使用數據庫時數據庫連接必須保持打開狀態(在這種狀態下無法進行與connection相關的操作)
3.它只能從前往後遍歷信息,不能中途停下修改數據
4.基於我前面說過的始終保持連接浪費資源,加上上面的第二條,那麼我們必須用完就關閉,如:
dr.close()或者如果我們怕忘記關閉,在實例化時給個參數commandbehavior.closeconnection
sqldatarader dr = cmd.executereader(commandbehavior.closeconnection);
DataReader的用法比較靈活,一般都是通過條件判斷來實現,如:
while(dr.reader())
{
................
}
也有人為了操作的某種目的,通過DataReader數據讀出來,然後存在一個新建的空DataTable中從而將DataReader轉化成了DataTable,這種做法究竟是否可取,還真是仁者見仁智者見智。如果您實在是想在DataTable和DataReader之間進行轉化,可以用下面的方法:
DataReader轉DataTable:
DataTable.Load(DataReader對象,LoadOption.OverwriteChanges);
DataTable轉DataReader:
DataReader Reader=DataTable.CreateDataReader()
二、非連接模式
非連接模式下擔負主要責任的兩個對象是DataAdapter和DataSet
非連接模式下DataAdapter起到了一個橋梁的作用,看到這個有的人可能會聯想到網絡適配器或電源適配器,沒錯,他們的功能都是一樣的,將各種不同的網絡類型電源類型轉化成統一能夠滿足要求的類型,這裡的DataAdapter就是數據適配器,將各種不同類型的數據源經過適配轉化成可以填入Dataset的數據。
DataAdatper對象的使用一般有兩種作用,一種是通過command對象如sqlcommand來執行sql語句,從數據源中檢測數據,並將檢索到的結果填充到DataSet中;還有一種就是把用戶對DataSet對象對數據的改變更新到數據源中去。
有人要忍不住問了,為什麼非連接模式不需要做這一步呢???
其實連接模式下通過command對象將所有對數據對象的單步操作都直接更新到數據庫裡去了,這叫單體操作。
而連接模式下Dataset因為和數據服務器斷開的,對單體的操作沒有機會隨時更新到數據庫裡去,這也就要求有這麼一個對象在所有的數據操作完成後對各種數據操作(如增刪改等操作)用各種對應的SQL命令統一更新到數據庫裡去,而這個對象就是DataAdapterle ,所以可以這麼說,DataAdapterle 采用的它內嵌的SQL命令集進行的批量SQL操作。
我們首先來看看command和dataadapter的實例化,一般我們可以這樣來實例化他們:
OleDbcommand olecmd=new OleDbcommand(sqlString,connObj);
OleDataAdapter oledpt=new OleDataAdapter(sqlString,connObj);
他們都都接收了一個SQL字符串和一個連接對象Connection,那麼Command和DataAdapter有什麼區別呢?
在面對sql語句時他們的區別是:
Command主要是運行純粹的SQL命令,直接使SQL語句的操作得以實施。
DataAdapter則內嵌著一套SQL的命令(也就是它的四個屬性),如select,delete,insert,update,等到需要執行其中之一的時候還是要Command對象來出面,即對內嵌的命令對象進行實例化,如果沒有實例化就調用,常常就會報錯,不能通過編譯(很多人在用dataadpter的update方法時就出錯),所以我們常常會這樣的用:
oledpt.selectcomand=new olecommand();
對於取數據
command結合excutereader()利用Datareader來實現
DataAdapter利用Fill()可以實現,但不應非要你用fill來實現。
這裡說說Fill()這個方法,打開DataAdapter可以發現,fill()方法來自他的父類的實現,其中Fill方法調用了FillFromCommand或FillFromReader方法。這兩個方法中也分別調用了command對象excutereader。所以接下來的事情就不難理解了,感興趣的朋友可以自己去看看fill的實現方法。
DataAdapter對象可以隱藏和Connection、Command對象溝通的細節,通過DataAdapter對象建立、初始化 DataTable,從而和DataSet對象結合起來在內存存放數據表副本,實現離線式數據庫操作。DataAdapter對象允許將DataSet對象中的數據保存到數據源中,也可以從數據源中讀取數據,並且也可以底層數據保存體進行數據的添加、刪除、更新等操作。
DataAdapter對象含有四個不同的操作命令,分別如下:
(1)、SelectCommand:用來或去數據源中的記錄;
(2)、InsertCommand:用來向數據源中新插入一條記錄;
(3)、UpdateCommand:用來更新數據源中的數據;
(4)、DeleteCommand:用來刪除數劇源中的記錄。
值得提出來特別說明的是,在實例化了DataAdapter對象後,此DataAdapter仍然是一個沒有實際作用的數據適配器,因為它對數據庫和數據集的操作實際上是通過它的四個Command對象(SelectCommand,InsertCommand,UpdateCommand,DeleteCommand)來實現的。所以我們實例化了SqlDataAdapter對象後需要再實例化它相關的SqlCommand對象
SqlAdapter.SelectCommand = new SqlCommand();
SqlAdapter.InsertCommand = new SqlCommand();
SqlAdapter.UpdateCommand = new SqlCommand();
SqlAdapter.DeleteCommand = new SqlCommand();
這四個SqlCommand的引用實際都指向一個SqlCommand對象的實例,另外,利用commandbuilder對象可以自動實例化三個命令(Insertcommand,DeleteCommand,Updatecommand)但注意,要自動生成三個命令須使用實例化好了的SelectCommand來檢索所需要的元素,那麼就需要注意DataAdapter的實例化方式了,如果采用空參數方法實例化則須單獨設置SelectCommand屬性,才可以使用commandbuilder,如:
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(queryString, connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
當如,如果是采用有參數實例化,則無須特別聲明selectCommand的屬性,因為這種有參數實例化的DataAdapter已經在實例化時自動完成了selectcommand屬性,如
SqlDataAdapter adapter = new SqlDataAdapter(“Select * from table",sqlconn);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
所以,一般空參數實例化的dataadapter與selectcommand屬性設置時同時出現的。有參數的dataadapter實例化是可以直接使用commandbuilder的。
DataSet的斷開模式是相對於數據服務器的斷開,不至於每次都要和數據服務器發生連接,而DataSet的數據實際是存在服務的高速緩存中(有的人誤以為是存在客戶端的,那就大錯特錯了,想一下便知道,那樣數據肯定是不安全的),這也就是說如果數據量大服務器的內存就浪費嚴重,這也是非連接模式的一個缺點,相比之下DataReader那種讀一行存一行的做法就節約內存多了。
三、回顧兩種模式的關系
兩種模式表面看起來走了兩條路線,但有很多共同點,最突出的要數以下兩個方面:
1、【開始相同】它們所需的數據連接的形式一樣,開始都要通過建立connection對象來完成連接
2、【最終相同】它們都需要在sqlcommand對象的配合下執行sql語句的操作,最終在sqlcommand對象的配合下實現對數據的增刪改查操作。
如連接模式的sql操作:
sqlcommand sqlcm=new sqlcommand();//很顯然是用了sqlcommand的實例對象
sqldatarader dr =sqlcm.excutereader();
? if(dr.HasRow)
? {
while(dr.read())
{
dr[""]..........//獲取字段的值
}
}
非連接模式的sql操作:
sqlDataAdapter slqad=new sqlDataAdapter();
sqlad.selectcommand=new sqlcommand(sqlstring,conn);//很顯然,這裡也用了sqlcommand