以往我们对数据库进行操作的方法是先连接上一个数据库,在保持连接的状态下进行数据的各种操作,如增删改查。这样的状况会有两个弊病,一是始终保持连接会造成资源的浪费,二是网络的各种不稳定因素会是这种连接发生丢失,从而对数据的操作也将丢失。
鉴于以上所说道的两个或更多的其他原因,微软提出了另一种操作模式,就是非连接模式的数据操作,当然也没有丢弃以前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