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