免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
asp.net夜話之七:ADO.NET介紹

Asp.net夜話之七:ADO.NET介紹
ADO.NET是對(duì)Microsoft ActiveX Data Objects (ADO)一個(gè)跨時(shí)代的改進(jìn),它提供了平臺(tái)互用性和可伸縮的數(shù)據(jù)訪問。由于傳送的數(shù)據(jù)都是XML格式的,因此任何能夠讀取XML格式的應(yīng)用程序都可以進(jìn)行數(shù)據(jù)處理。事實(shí)上,接受數(shù)據(jù)的組件不一定要是ADO .NET組件,它可以是基于一個(gè)Microsoft Visual Studio的解決方案,也可以是任何運(yùn)行在其它平臺(tái)上的任何應(yīng)用程序。
以前做數(shù)據(jù)庫訪問的時(shí)候,需要一直與數(shù)據(jù)庫保持連接,直到獲取完所有滿足需要的數(shù)據(jù)之后才會(huì)斷開數(shù)據(jù)庫連接,這種數(shù)據(jù)庫訪問方式稱之為連接式數(shù)據(jù)訪問技術(shù)。相比于以前的連接式數(shù)據(jù)訪問技術(shù),ADO.NET除了提供連接式數(shù)據(jù)訪問技術(shù)之外,還提供了另一種斷開式解決方案,那就是在內(nèi)存中模擬一個(gè)數(shù)據(jù)庫,也就是內(nèi)存中的數(shù)據(jù)庫。
我們知道在實(shí)際的數(shù)據(jù)庫技術(shù)中,每個(gè)數(shù)據(jù)庫就是一個(gè)業(yè)務(wù)邏輯單元,一般來說這個(gè)數(shù)據(jù)庫包含了實(shí)現(xiàn)一個(gè)應(yīng)用軟件或者一個(gè)網(wǎng)站所需要的全部數(shù)據(jù)。在這里數(shù)據(jù)庫就是頂級(jí)對(duì)象,我們引用創(chuàng)建數(shù)據(jù)庫時(shí)所用到的名詞database來表示(因?yàn)閯?chuàng)建數(shù)據(jù)庫的SQL語句是create database),在一個(gè)數(shù)據(jù)庫里可以包含有多個(gè)表(table)和視圖(view),除此之外還可以包含有一些外鍵關(guān)系等。在一個(gè)表(table)或者視圖(view)里可以包含多個(gè)列(column)和行(row)。
在ADO.NET中對(duì)上面提到的對(duì)象都在內(nèi)存中進(jìn)行了模擬,在內(nèi)存中的數(shù)據(jù)庫對(duì)象稱之為DataSet,一個(gè)內(nèi)存中的數(shù)據(jù)庫(DataSet)可以包含多個(gè)在內(nèi)存中的表(DataTable)和內(nèi)存中的視圖(DataView),并且也允許在表存在一些關(guān)系(DataRelation)。同時(shí)在一個(gè)內(nèi)存中的表(DataTable)或者內(nèi)存中的視圖(DataView)中也允許存在行(DataRow)和列(DataColumn)。
物理數(shù)據(jù)庫與內(nèi)存數(shù)據(jù)庫之間的各對(duì)象的對(duì)應(yīng)關(guān)系如下:
 


在上圖中顏色相同的表示二者基本上是一種對(duì)應(yīng)關(guān)系。

在本篇將講述6個(gè)ADO.NET中的常用對(duì)象:
Connection對(duì)象
Command對(duì)象
DataReader對(duì)象
DataAdapter對(duì)象
DataSet對(duì)象
DataTable對(duì)象
DataRow對(duì)象
DataColumn對(duì)象
參數(shù)化SQL語句
分頁查詢SQL語句

嚴(yán)格地說,在.net類庫中并沒有Connection、Command、DataAdapter和DataReader對(duì)象的,這是對(duì)相關(guān)的對(duì)象做了一個(gè)抽象。在實(shí)際的開發(fā)中,我們經(jīng)常用到的數(shù)據(jù)庫有Access、SQL Server、Oracle、MySQL等,盡管大部分都遵循SQL國際化標(biāo)準(zhǔn),但是它們?cè)谧裱瓨?biāo)準(zhǔn)的前提下又做了一些擴(kuò)充,并且即使遵循了相同的標(biāo)準(zhǔn),但是實(shí)現(xiàn)方法并不相同,所以在某些情況下實(shí)現(xiàn)相同的功能可能在不同的數(shù)據(jù)庫中SQL語句并不相同。
于是,在ADO.NET也定義了一套用于訪問數(shù)據(jù)庫的標(biāo)準(zhǔn),當(dāng)然這個(gè)標(biāo)準(zhǔn)是以接口(interface)的形式提供的,各數(shù)據(jù)庫廠商只要實(shí)現(xiàn)了這個(gè)接口就能在ADO.NET下正常工作(這也是接口的作用,接口就是用于指定規(guī)范,自己本身并不實(shí)現(xiàn),在Java中針對(duì)數(shù)據(jù)庫訪問也有一套接口留待各數(shù)據(jù)庫來實(shí)現(xiàn))。當(dāng)然在.net類庫中微軟已經(jīng)提供對(duì)Access、SQL Server和Oracle數(shù)據(jù)庫對(duì)上面提到的接口的實(shí)現(xiàn)。
在ADO.NET中定義的這一套接口是IDbConnection、IDbCommand、IDbDataAdapter和IDataReader,并且還有一套實(shí)現(xiàn)這些接口的抽象類,分別是DbConnection、DbCommand、DbDataAdapter和DataReader。

 
上圖最上面的是數(shù)據(jù)庫訪問接口,緊接著的是數(shù)據(jù)庫訪問抽象類,下面是針對(duì)不同數(shù)據(jù)庫中實(shí)現(xiàn)這些接口的類,并且在括號(hào)中注明了其所在的命名空間,比如針對(duì)MySQL數(shù)據(jù)的數(shù)據(jù)庫訪問類就位于MySql.Data.MySqlClient命名空間下,關(guān)于MySql的數(shù)據(jù)庫訪問類需要到MySql數(shù)據(jù)庫的官方網(wǎng)站去下載,它的官方網(wǎng)站是http://www.mysql.com。其它的數(shù)據(jù)庫訪問類都在.net類庫中自帶了。
注意:訪問SQL Server7.0以下版本的SQL Server數(shù)據(jù)庫時(shí)需要用System.Data.OleDb命名空間下一套數(shù)據(jù)庫訪問類,雖然這一套數(shù)據(jù)庫訪問類同樣也能訪問SQL Server2000以上版本,但是沒有辦法利用SQL Server數(shù)據(jù)庫的一些新特性,所以不建議使用System.Data.OleDb命名空間下的類訪問SQL Server2000以上的版本。
在本篇的講述中,針對(duì)SQL Server數(shù)據(jù)庫講述Connection、Command、DataAdapter和DataReader對(duì)象的用法,它們?cè)谄渌鼣?shù)據(jù)庫中也有對(duì)應(yīng)的類,除了有些SQL語句語法不一樣之外,用法是基本一樣的。

Connection對(duì)象
Connection對(duì)象也稱為數(shù)據(jù)庫連接對(duì)象,Connection對(duì)象的功能是負(fù)責(zé)對(duì)數(shù)據(jù)源的連接。所有Connection對(duì)象的基類都是DbConnection類。
Connection對(duì)象有兩個(gè)重要屬性:
ConnectionString:表示用于打開 SQL Server 數(shù)據(jù)庫的字符串;
State:表示 Connection 的狀態(tài),有Closed和Open兩種狀態(tài)。
Connection對(duì)象有兩個(gè)重要方法:
Open()方法:指示打開數(shù)據(jù)庫;
Close()方法:指示關(guān)閉數(shù)據(jù)庫。
在實(shí)際開發(fā)中很多朋友經(jīng)常詢問數(shù)據(jù)庫連接字符串該怎么寫,其實(shí)有一個(gè)很簡單的技巧,我們可以在Visual Studio 2005工具箱中找到數(shù)據(jù)分組,如下圖:

 
打開或新建一個(gè)asp.net頁面,在設(shè)計(jì)視圖下雙擊SqlDataSource控件就會(huì)添加一個(gè)SqlDataSource到當(dāng)前頁面,如下圖:
 
當(dāng)我們用鼠標(biāo)單擊SqlDataSouce控件時(shí)會(huì)出現(xiàn)一個(gè)小三角箭頭,如上圖所示,當(dāng)我們點(diǎn)擊這個(gè)三角箭頭時(shí)會(huì)出現(xiàn)如下圖所示的界面:
 
點(diǎn)擊“配置數(shù)據(jù)源”時(shí)會(huì)出現(xiàn)下面的界面:
 
點(diǎn)“新建連接”后出現(xiàn)如下界面:
 
在這個(gè)界面中默認(rèn)是連接到SQL Server數(shù)據(jù)庫,其實(shí)我們還可以利用這個(gè)向?qū)нB接到其它數(shù)據(jù)庫的,我們點(diǎn)擊“數(shù)據(jù)源”旁邊的“更改”按鈕出現(xiàn)如下圖所示的界面:
 
從上面的界面中我們可以看出可以利用這個(gè)連接向?qū)渲眠B接到Access數(shù)據(jù)庫文件、ODBC數(shù)據(jù)源、SQL Server數(shù)據(jù)庫、SQL Server手機(jī)版數(shù)據(jù)庫、SQL Server數(shù)據(jù)庫文件、Oracle數(shù)據(jù)庫文件及其它數(shù)據(jù)庫。
在這里我們選擇Microsoft SQL Server選項(xiàng),連接到SQL Server數(shù)據(jù)庫。如果我們?cè)诰钟蚓W(wǎng)中,我們可以點(diǎn)擊“添加連接”界面中的刷新按鈕來查看局域網(wǎng)中有哪些SQL Server數(shù)據(jù)庫可以連接。連接到數(shù)據(jù)庫可以用下面的方式:
(1)如果要連接的數(shù)據(jù)庫服務(wù)器與開發(fā)者的機(jī)器在同一個(gè)局域網(wǎng)里,可以使用局域網(wǎng)IP地址或者局域網(wǎng)中的電腦主機(jī)名;
(2)如果要連接的數(shù)據(jù)庫服務(wù)器與開發(fā)者的機(jī)器不在同一個(gè)局域網(wǎng)內(nèi),那么就要求數(shù)據(jù)庫服務(wù)器必須有一個(gè)公網(wǎng)IP,我們可以使用公網(wǎng)IP來連接,如果數(shù)據(jù)庫服務(wù)器還有互聯(lián)網(wǎng)域名,那么用互聯(lián)網(wǎng)域名也是可以的。
(3)如果要連接的數(shù)據(jù)庫服務(wù)器與開發(fā)者所使用的機(jī)器是同一臺(tái)機(jī)器,那么可以使用以下幾種方式之一:”(local)”或者”.”或者”127.0.0.1”。
需要注意的是,如果在一臺(tái)機(jī)器上運(yùn)行者同一種數(shù)據(jù)庫的不同版本,比如說在”zhoufoxcn”這臺(tái)主機(jī)上同時(shí)運(yùn)行著SQL 2000、SQL 2005和SQL Express三種版本,并且它們所使用的Windows服務(wù)名分別為”SQL2000”、”SQL2005”和”SQLExpress”,那么我們要連接到SQL 2000這個(gè)數(shù)據(jù)庫上所使用的服務(wù)器名就應(yīng)該填寫”zhoufoxcn/SQL2000”這種“主機(jī)名/實(shí)例名”的方式或者“主機(jī)IP/實(shí)例名”,這種情況在同時(shí)安裝了Visual Studio 2005和SQL 2005的朋友那里很常見,因?yàn)镾QL Express是針對(duì)學(xué)生的功能有限的免費(fèi)版本,這個(gè)版本的數(shù)據(jù)庫在安裝Visual Studio 2005時(shí)默認(rèn)是一同安裝的。
在上面的“添加連接”窗口,我們分別填寫如下信息:
 
在上面我們連接的是本機(jī)上的數(shù)據(jù)庫,所使用的數(shù)據(jù)庫賬號(hào)是sa,訪問的數(shù)據(jù)庫是AspNetStudy,創(chuàng)建這個(gè)數(shù)據(jù)的SQL腳本如下:

  1. IF EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N'AspNetStudy')

  2.  DROP DATABASE [AspNetStudy]

  3. GO

  4. CREATE DATABASE [AspNetStudy]  ON (NAME = N'AspNetStudy_Data', FILENAME = N'C:/Program Files/Microsoft SQL Server/MSSQL/data/AspNetStudy_Data.MDF' , SIZE = 1, FILEGROWTH = 10%) LOG ON (NAME = N'AspNetStudy_Log', FILENAME = N'C:/Program Files/Microsoft SQL Server/MSSQL/data/AspNetStudy_Log.LDF' , SIZE = 1, FILEGROWTH = 10%)

  5.  COLLATE Chinese_PRC_CI_AS

  6. GO

  7. use [AspNetStudy]

  8. GO

  9. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[UserInfo]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)

  10. drop table [dbo].[UserInfo]

  11. GO

  12. CREATE TABLE [dbo].[UserInfo] (

  13.  [UserID] [int] IDENTITY (1, 1) NOT NULL ,

  14.  [UserName] [varchar] (20) COLLATE Chinese_PRC_CI_AS NOT NULL ,

  15.  [RealName] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NOT NULL ,

  16.  [Age] [tinyint] NOT NULL ,

  17.  [Sex] [bit] NOT NULL ,

  18.  [Mobile] [char] (11) COLLATE Chinese_PRC_CI_AS NULL ,

  19.  [Phone] [char] (11) COLLATE Chinese_PRC_CI_AS NULL ,

  20.  [Email] [varchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL 

  21. ) ON [PRIMARY]

  22. GO

  23.  CREATE  UNIQUE  INDEX [IX_UserName] ON [dbo].[UserInfo]([UserName]) WITH  IGNORE_DUP_KEY  ON [PRIMARY]

  24. GO

  25. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('zhangfei','張飛',36,'13455663420','03517890360','zhangfei@msn.com',1);

  26. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('guanyu','關(guān)羽',38,'13455663421','03517890361','guanyu@163.com',1);

  27. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('liubei','劉備',42,'13455663422','03517890362','liubei@163.net',1);

  28. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('zhougong','周公',29,'13455663423','03517890363','zhoufoxcn@tom.com',1);

  29. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('zhaoyun','趙云',32,'13455663424','03517890364','zhaoyun@sohu.com',1);

  30. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('huanggai','黃蓋',50,'13455663425','03517890365','huanggai@live.com',1);

  31. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('zhugeliang','諸葛亮',27,'13455663426','03517890366','zhugeliang@hotmail.com',1);

  32. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('jiangwei','姜維',22,'13455663427','03517890367','jiangwei@netease.com',1);

  33. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('caocao','曹操',48,'13455663428','03517890368','caocao@qq.com',1);

  34. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('guojia','郭嘉',32,'13455663429','03517890369','guojia@21cn.com',1);

  35. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('sunquan','孫權(quán)',33,'13455663430','03517890370','sunquan@gmail.com',1);

  36. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('diaochan','貂禪',20,'13455663431','03517890371','diaochan@sina.com.cn',0);

  37. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('yangyuhuan','楊玉環(huán)',24,'13455663432','03517890372','yangyuhuang@chinaren.com',0);

  38. insert into UserInfo([UserName],[RealName],[Age],[Mobile],[Phone],[Email],[Sex])values('wangzhaojun','王昭君',26,'13455663433','03517890373','wangzhaojun@yahoo.com.cn',0);

  39. go


我們可以點(diǎn)擊一下“測試連接”按鈕,如果彈出連接成功的提示消息就表示這個(gè)數(shù)據(jù)庫連接是可用的。點(diǎn)擊“確定”按鈕,回到“配置數(shù)據(jù)源”界面,這時(shí)候點(diǎn)擊連接字符串旁邊的”+”按鈕就可以看到數(shù)據(jù)庫的連接字符串信息,如下圖所示:

 
把這個(gè)字符串拷貝到我們需要實(shí)例化Connection對(duì)象的地方,可以作為構(gòu)造函數(shù)的參數(shù)實(shí)例化一個(gè)SqlConnection對(duì)象。
由于這個(gè)例子前后臺(tái)代碼都比較簡單,所以在Visual Studio 2005建立的單頁模式網(wǎng)頁(代碼和頁面都在一個(gè)頁面里),下面是代碼:

  1. <%@ Page Language='C#' %>

  2. <%@ Import Namespace='System.Data.SqlClient' %>

  3. <%@ Import Namespace='System.Data' %>

  4. <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>

  5. <script runat='server'>

  6.     protected void Page_Load(object sender, EventArgs e)

  7.     {

  8.         SqlConnection connection = new SqlConnection('Data Source=(local);Initial Catalog=AspNetStudy;Persist Security Info=True;User ID=sa;Password=sa');

  9.         //注意,DateTime.Now.ToString('yyyy-MM-dd HH:mm:ss')是將當(dāng)前時(shí)間格式化為類似于2008-10-09 00:00:03的形式的字符串

  10.         Response.Write('時(shí)間'+ DateTime.Now.ToString('yyyy-MM-dd HH:mm:ss')+'當(dāng)前數(shù)據(jù)庫連接狀態(tài)是:'+connection.State +'<br/>');

  11.         connection.Open();

  12.         Response.Write('時(shí)間' + DateTime.Now.ToString('yyyy-MM-dd HH:mm:ss') + '當(dāng)前數(shù)據(jù)庫連接狀態(tài)是:' + connection.State + '<br/>');

  13.         connection.Close();

  14.         Response.Write('時(shí)間' + DateTime.Now.ToString('yyyy-MM-dd HH:mm:ss') + '當(dāng)前數(shù)據(jù)庫連接狀態(tài)是:' + connection.State + '<br/>');

  15.     }

  16. </script>

  17. <html xmlns='http://www.w3.org/1999/xhtml' >

  18. <head runat='server'>

  19.     <title>無標(biāo)題頁</title>

  20. </head>

  21. <body>

  22.     <form id='form1' runat='server'>

  23.     <div>

  24.          </div>

  25.     </form>

  26. </body>

  27. </html>

以下是運(yùn)行效果:

 
可見實(shí)例化一個(gè)Connection對(duì)象的時(shí)候,被實(shí)例化的Connection對(duì)象是關(guān)閉的,我們需要Open這個(gè)Connection對(duì)象,執(zhí)行完畢相關(guān)操作之后再關(guān)閉這個(gè)Connection對(duì)象。

Command對(duì)象
Command對(duì)象也稱為數(shù)據(jù)庫命令對(duì)象,Command對(duì)象主要執(zhí)行包括添加、刪除、修改及查詢數(shù)據(jù)的操作的命令。也可以用來執(zhí)行存儲(chǔ)過程。用于執(zhí)行存儲(chǔ)過程時(shí)需要將Command對(duì)象的CommandType 屬性設(shè)置為CommandType.StoredProcedure,默認(rèn)情況下CommandType 屬性為CommandType.Text,表示執(zhí)行的是普通SQL語句。
Command主要有三個(gè)方法:
ExecuteNonQuery () :執(zhí)行一個(gè)SQL語句,返回受影響的行數(shù),這個(gè)方法主要用于執(zhí)行對(duì)數(shù)據(jù)庫執(zhí)行增加、更新、刪除操作,注意查詢的時(shí)候不是調(diào)用這個(gè)方法。
ExecuteReader ():執(zhí)行一個(gè)查詢的SQL語句,返回一個(gè)DataReader對(duì)象。
ExecuteScalar ():從數(shù)據(jù)庫檢索單個(gè)值。這個(gè)方法主要用于統(tǒng)計(jì)操作。

有關(guān)ExecuteNonQuery ()和ExecuteReader ()的用法在稍后馬上提到,這里我主要演示ExecuteScalar ()這個(gè)方法的用法。
請(qǐng)看下面的例子:

 
我們可以看到上面的SQL語句執(zhí)行的結(jié)果是一行一列的結(jié)果集,ExecuteScalar ()這個(gè)方法就是針對(duì)這種情況的,這個(gè)方法只返回查詢結(jié)果集的第一行第一列。
同樣,因?yàn)檫@個(gè)頁面的代碼和設(shè)計(jì)部分非常簡單,仍然采用的單頁模式,代碼如下:

  1. <%@ Page Language='C#' %>

  2. <%@ Import Namespace='System.Data.SqlClient' %>

  3. <%@ Import Namespace='System.Data' %>

  4. <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>

  5. <script runat='server'>

  6.     protected void Page_Load(object sender, EventArgs e)

  7.     {

  8.         //實(shí)例化Connection對(duì)象

  9.         SqlConnection connection = new SqlConnection('Data Source=(local);Initial Catalog=AspNetStudy;Persist Security Info=True;User ID=sa;Password=sa');

  10.         //實(shí)例化Command對(duì)象

  11.         SqlCommand command = new SqlCommand('select count(1) as 男性人數(shù) from UserInfo where sex=1', connection);

  12.         //打開Connection對(duì)象

  13.         connection.Open();

  14.         //執(zhí)行SQL語句

  15.         int count = int.Parse(command.ExecuteScalar().ToString());

  16.         //關(guān)閉Connection對(duì)象

  17.         connection.Close();

  18.         Response.Write('在UserInfo表里共有' + count + '個(gè)男性。');

  19.     }

  20. </script>

  21. <html xmlns='http://www.w3.org/1999/xhtml' >

  22. <head runat='server'>

  23.     <title>無標(biāo)題頁</title>

  24. </head>

  25. <body>

  26.     <form id='form1' runat='server'>

  27.     <div>

  28.     </div>

  29.     </form>

  30. </body>

  31. </html>

這個(gè)頁面執(zhí)行的結(jié)果如下:

 
在操作數(shù)據(jù)庫的時(shí)候,為了提高性能,都遵循一個(gè)原則:數(shù)據(jù)庫連接對(duì)象應(yīng)該盡可能晚打開,盡可能早關(guān)閉。在上面的例子中,在Command對(duì)象需要執(zhí)行數(shù)據(jù)庫操作之前才打開數(shù)據(jù)庫連接對(duì)象,執(zhí)行數(shù)據(jù)庫操作之后馬上就關(guān)閉了數(shù)據(jù)庫連接對(duì)象。希望初學(xué)者們記住這個(gè)原則。


DataReader對(duì)象
DataReader對(duì)象是一個(gè)讀取行的只讀流的方式,綁定數(shù)據(jù)時(shí)比使用數(shù)據(jù)集方式性能要高,因?yàn)樗侵蛔x的,所以如果要對(duì)數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行修改就需要借助其它方法將所作的更改保存到數(shù)據(jù)庫。
DataReader對(duì)象不能通過直接實(shí)例化,必須借助與相關(guān)的Command對(duì)象來創(chuàng)建實(shí)例,例如用SqlCommand的實(shí)例的ExecuteReader()方法可以創(chuàng)建SqlDataReader實(shí)例。
因?yàn)镈ataReader對(duì)象讀取數(shù)據(jù)時(shí)需要與數(shù)據(jù)庫保持連接,所以在使用完DataReader對(duì)象讀取完數(shù)據(jù)之后應(yīng)該立即調(diào)用它的Close()方法關(guān)閉,并且還應(yīng)該關(guān)閉與之相關(guān)的Connection對(duì)象。在.net類庫中提供了一種方法,在關(guān)閉DataReader對(duì)象的同時(shí)自動(dòng)關(guān)閉掉與之相關(guān)的Connection對(duì)象,使用這種方法是可以為ExecuteReader()方法指定一個(gè)參數(shù),如:
SqlDataReader reader =command.ExecuteReader(CommandBehavior.CloseConnection);
CommandBehavior是一個(gè)枚舉,上面使用了CommandBehavior枚舉的CloseConnection值,它能在關(guān)閉SqlDataReader時(shí)關(guān)閉相應(yīng)的SqlConnection對(duì)象。
并且DataReader對(duì)象讀取數(shù)據(jù)有三種方式:
一種是按查詢的時(shí)候列的索引用指定的方式來讀取列值,無需做相應(yīng)轉(zhuǎn)換,如GetByte(int i)就是讀取第i列的值并且轉(zhuǎn)換成byte類型的值。第這種方法的優(yōu)點(diǎn)是指定列后直接將該列的直接讀取出來了,無需再轉(zhuǎn)換,缺點(diǎn)是一旦指定的列不能按照指定的方式轉(zhuǎn)換時(shí)就會(huì)拋出異常,比如數(shù)據(jù)庫里字段的類型是string類型或者該字段的值為空時(shí)按照GetByte(i)這種方式讀取會(huì)拋出異常。
第二種方式就是按照列索引的方式讀取,在讀取的時(shí)候并不進(jìn)行值轉(zhuǎn)換,如:reader[5]就是讀取第5列的值(這里reader是一個(gè)Reader對(duì)象的實(shí)例),這樣得到的值是一個(gè)object類型的值,這也很好理解,因?yàn)樵跀?shù)據(jù)庫可能存儲(chǔ)各種類型的值,而object是所有類的基類,所以這個(gè)方法不會(huì)拋出異常。如果要得到它的正確類型,還需要根據(jù)數(shù)據(jù)庫里的字段進(jìn)行進(jìn)行相應(yīng)轉(zhuǎn)換。
最后一種是按照列名的方式去讀,并且在讀的時(shí)候也不進(jìn)行相應(yīng)轉(zhuǎn)換,得到的是object類型的值。
綜合前面三種方式各有特點(diǎn),第一種方式最直接,但是有可能拋出異常,第二種方式比第一種稍微靈活一些,我們可以根據(jù)讀取到值為空(在.net里用DBNull類來表示,可以表示數(shù)據(jù)庫中任意數(shù)據(jù)類型的空值),我們就不進(jìn)行相應(yīng)的類型轉(zhuǎn)換,避免出現(xiàn)異常。第三種方式按照列的名字來讀取數(shù)據(jù),也需要按照第二種方式進(jìn)行一定的轉(zhuǎn)換。就性能來說第一種最高,第二種稍低,第三種最低(這很好理解,假設(shè)要在一個(gè)旅館里找人直通過房間號(hào)找肯定比通過名字找快),就靈活性來說第三種最靈活,第二種次之,第一種最不靈活(假如在后來編寫SQL語句中更改了列的索引,第一種和第二種都可能出現(xiàn)問題)。實(shí)際開發(fā)中根據(jù)實(shí)際情況選擇合適的方式。
下面是一個(gè)使用DataReader對(duì)象讀取數(shù)據(jù)的例子,因?yàn)榇a不是很多并且也不復(fù)雜,所以采用了單頁模式,并且還演示了三種讀取數(shù)據(jù)的方式,代碼如下:

  1. <%@ Page Language='C#' %>

  2. <%@ Import Namespace='System.Data.SqlClient' %>

  3. <%@ Import Namespace='System.Data' %>

  4. <%@ Import Namespace='System.Text' %>

  5. <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>

  6. <script runat='server'>

  7. //注:為了方便沒有使用代碼頁面方式,實(shí)際開發(fā)中這種做大很少見

  8.     protected void Page_Load(object sender, EventArgs e)

  9.     {

  10.     }

  11.     public void ShowData()

  12.     {

  13.         //實(shí)例化Connection對(duì)象

  14.         SqlConnection connection = new SqlConnection('Data Source=(local);Initial Catalog=AspNetStudy;Persist Security Info=True;User ID=sa;Password=sa');

  15.         //實(shí)例化Command對(duì)象

  16.         SqlCommand command = new SqlCommand('select * from UserInfo where sex=1', connection);

  17.         //打開Connection對(duì)象

  18.         connection.Open();

  19.         //得到DataReader的實(shí)例,注意使用了CommandBehavior這個(gè)參數(shù),以便同時(shí)關(guān)閉Connection

  20.         SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);

  21.         //如果當(dāng)前記錄還有下一條記錄,則循環(huán)不會(huì)終止

  22.         while (reader.Read())

  23.         {

  24.             Response.Write('<tr><td>' + reader.GetInt32(0) + '</td>');//按照列順序和對(duì)應(yīng)類型直接讀取值

  25.             Response.Write('<td>' + reader.GetString(1) + '</td>');//按照列順序和對(duì)應(yīng)類型直接讀取值

  26.             Response.Write('<td>' + reader.GetString(2) + '</td>');//按照列順序和對(duì)應(yīng)類型直接讀取值

  27.             Response.Write('<td>' + reader.GetByte(3) + '</td>');//按照列順序和對(duì)應(yīng)類型直接讀取值

  28.             //下面是按照列順序直接讀取值,并且根據(jù)值來判斷最終顯示結(jié)果

  29.             Response.Write('<td>' + (reader.GetBoolean(4)==true?'男':'女') + '</td>');

  30.             //根據(jù)列順序讀,列的值需要做相應(yīng)轉(zhuǎn)換

  31.             Response.Write('<td>' + reader[5].ToString() + '</td>');

  32.             //根據(jù)列名來讀取,列的值需要做相應(yīng)轉(zhuǎn)換

  33.             Response.Write('<td>' + reader['Phone'] + '</td>');

  34.             Response.Write('<td>' + reader['Email'].ToString() + '</td></tr>/n');

  35.         }

  36.         reader.Close();

  37.     }

  38. </script>

  39. <html xmlns='http://www.w3.org/1999/xhtml' >

  40. <head runat='server'>

  41.     <title>無標(biāo)題頁</title>

  42. </head>

  43. <body>

  44.     <form id='form1' runat='server'>

  45.     <div>

  46.     <table border='1' cellpadding='0' cellspacing='0'>

  47.     <tr><td>編號(hào)</td><td>賬號(hào)</td><td>真實(shí)姓名</td><td>年齡</td><td>性別</td><td>手機(jī)</td><td>電話</td><td>電子郵件</td></tr>

  48.     <% 

  49.         //在頁面中調(diào)用后臺(tái)代碼,這樣也能保證生成的代碼不會(huì)位于<html></html>標(biāo)記之外

  50.         ShowData(); 

  51.     %>

  52.     </table>

  53.     </div>

  54.     </form>

  55. </body>

  56. </html>

下面是運(yùn)行結(jié)果:

 

DataAdapter對(duì)象
DataAdapter對(duì)象也稱之為數(shù)據(jù)適配器對(duì)象,DataAdapter對(duì)象利用數(shù)據(jù)庫連接對(duì)象(Connection)連接的數(shù)據(jù)源,使用數(shù)據(jù)庫命令對(duì)象(Command)規(guī)定的操作從數(shù)據(jù)源中檢索出數(shù)據(jù)送往數(shù)據(jù)集對(duì)象(DataSet),或者將數(shù)據(jù)集中經(jīng)過編輯后的數(shù)據(jù)送回?cái)?shù)據(jù)源。
數(shù)據(jù)適配器將數(shù)據(jù)填入數(shù)據(jù)集時(shí)調(diào)用方法Fill(),語句如下:

  1. dataAdapter1.Fill (dataTable);//直接填充表

  或者

  1. dataAdapter1.Fill (dataSet11, 'Products');//填充dataSet11數(shù)據(jù)集中的'Products'表

當(dāng)dataAdapter1調(diào)用Fill() 方法時(shí)將使用與之相關(guān)聯(lián)的命令組件所指定的 SELECT 語句從數(shù)據(jù)源中檢索行。然后將行中的數(shù)據(jù)添加到 DataSet 中的DataTable 對(duì)象中或者直接填充到DataTable的實(shí)例中,如果 DataTable 對(duì)象不存在,則自動(dòng)創(chuàng)建該對(duì)象。
當(dāng)執(zhí)行上述SELECT語句時(shí),與數(shù)據(jù)庫的連接必須有效,但不需要用語句將連接對(duì)象打開。如果調(diào)用Fill()方法之前與數(shù)據(jù)庫的連接已經(jīng)關(guān)閉,則將自動(dòng)打開它以檢索數(shù)據(jù),執(zhí)行完畢后再自動(dòng)將其關(guān)閉。如果調(diào)用Fill()方法之前連接對(duì)象已經(jīng)打開,則檢索后繼續(xù)保持打開狀態(tài)。
注意:一個(gè)數(shù)據(jù)集中可以放置多張數(shù)據(jù)表。但是每個(gè)數(shù)據(jù)適配器只能夠?qū)?yīng)于一張數(shù)據(jù)表。

DataSet對(duì)象
DataSet對(duì)象也稱為數(shù)據(jù)集對(duì)象,DataSet對(duì)象用于表示那些儲(chǔ)存在內(nèi)存中的數(shù)據(jù),它相當(dāng)于一個(gè)內(nèi)存中的數(shù)據(jù)庫。它可以包括多個(gè)DataTable對(duì)象及DataView對(duì)象。DataSet主要用于管理存儲(chǔ)在內(nèi)存中的數(shù)據(jù)以及對(duì)數(shù)據(jù)的斷開操作。
由于DataSet對(duì)象提供了一個(gè)離線的數(shù)據(jù)源,這樣減輕了數(shù)據(jù)庫以及網(wǎng)絡(luò)的負(fù)擔(dān),在設(shè)計(jì)程序的時(shí)候可以將DataSet對(duì)象作為程序的數(shù)據(jù)源。
下面是一個(gè)利用Adapter對(duì)象填充數(shù)據(jù)到DataTable(或DataSet)并顯示的例子,這個(gè)例子采用了頁面和代碼分離模式,前臺(tái)代碼如下:

  1. <%@ Page Language='C#' AutoEventWireup='true' CodeFile='DataAdapter.aspx.cs' Inherits='DataAdapter' %>

  2. <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>

  3. <html xmlns='http://www.w3.org/1999/xhtml' >

  4. <head runat='server'>

  5.     <title>利用Adapter對(duì)象填充DataTable的例子</title>

  6. </head>

  7. <body>

  8.     <form id='form1' runat='server'>

  9.     <div>

  10.     <table border='1' cellpadding='0' cellspacing='0'>

  11.     <tr><td>編號(hào)</td><td>賬號(hào)</td><td>真實(shí)姓名</td><td>年齡</td><td>性別</td><td>手機(jī)</td><td>電話</td><td>電子郵件</td></tr>

  12.     <% 

  13.         //在頁面中調(diào)用后臺(tái)代碼,這樣也能保證生成的代碼不會(huì)位于<html></html>標(biāo)記之外

  14.         ShowData(); 

  15.     %>

  16.     </table>

  17.     </div>

  18.     </form>

  19. </body>

  20. </html>

相應(yīng)的后臺(tái)代碼:

  1. using System;

  2. using System.Data;

  3. using System.Configuration;

  4. using System.Collections;

  5. using System.Web;

  6. using System.Web.Security;

  7. using System.Web.UI;

  8. using System.Web.UI.WebControls;

  9. using System.Web.UI.WebControls.WebParts;

  10. using System.Web.UI.HtmlControls;

  11. using System.Data.SqlClient;

  12. public partial class DataAdapter : System.Web.UI.Page

  13. {

  14.     protected void Page_Load(object sender, EventArgs e)

  15.     {

  16.     }

  17.     //供前臺(tái)頁面調(diào)用的方法,這個(gè)方法必須是protected或者public

  18.     protected void ShowData()

  19.     {

  20.         //實(shí)例化Connection對(duì)象

  21.         SqlConnection connection = new SqlConnection('Data Source=(local);Initial Catalog=AspNetStudy;Persist Security Info=True;User ID=sa;Password=sa');

  22.         //實(shí)例化Command對(duì)象

  23.         SqlCommand command = new SqlCommand('select * from UserInfo where sex=0', connection);

  24.         SqlDataAdapter adapter = new SqlDataAdapter(command);

  25.         /*

  26.          下面的被注釋掉的代碼與上面的代碼是等效的

  27.         SqlDataAdapter adapter = new SqlDataAdapter('select * from UserInfo where sex=0', connection);

  28.          */

  29.         DataTable data = new DataTable();

  30.         adapter.Fill(data);

  31.         /* 下面的被注釋掉語句與上面填充DataTable的效果是一樣的,我更傾向于沒有注釋掉的部分

  32.         DataSet ds = new DataSet();//實(shí)例化DataSet

  33.         adapter.Fill(ds, 'UserInfo');//填充ds中的'UserInfo'表

  34.         DataTable data = ds.Tables['UserInfo'];

  35.         */

  36.         for (int i = 0; i < data.Rows.Count; i++)

  37.         {

  38.             Response.Write('<tr><td>' + data.Rows[i]['UserId'].ToString() + '</td>');

  39.             Response.Write('<td>' + data.Rows[i]['UserName'].ToString() + '</td>');

  40.             Response.Write('<td>' + data.Rows[i]['RealName'].ToString() + '</td>');

  41.             Response.Write('<td>' + data.Rows[i]['Age'].ToString() + '</td>');

  42.             //下面是按照列順序直接讀取值,并且根據(jù)值來判斷最終顯示結(jié)果

  43.             Response.Write('<td>' + (bool.Parse(data.Rows[i]['Sex'].ToString()) == true ? '男' : '女') + '</td>');

  44.             //根據(jù)列順序讀,列的值需要做相應(yīng)轉(zhuǎn)換

  45.             Response.Write('<td>' + data.Rows[i]['Mobile'].ToString() + '</td>');

  46.             //根據(jù)列名來讀取,列的值需要做相應(yīng)轉(zhuǎn)換

  47.             Response.Write('<td>' + data.Rows[i]['Phone'].ToString() + '</td>');

  48.             Response.Write('<td>' + data.Rows[i]['Email'].ToString() + '</td></tr>/n');

  49.         }

  50.     }

  51. }

上面的程序代碼基本與使用DataReader對(duì)象的例子相同,不過這里查詢的所有女性用戶,效果如下:

 

DataTable對(duì)象
DataTable 是 ADO.NET 庫中的核心對(duì)象,就像普通的數(shù)據(jù)庫中的表一樣,它也有行和列。它主要包括DataRow和DataColumn,分別代表行和列。
(1) 數(shù)據(jù)行(DataRow)
數(shù)據(jù)行是給定數(shù)據(jù)表中的一行數(shù)據(jù),或者說是數(shù)據(jù)表中的一條記錄。它可能代表一個(gè)學(xué)生、一位用戶、一張訂單或者一件貨物的相關(guān)數(shù)據(jù)。DataRow對(duì)象的方法提供了對(duì)表中數(shù)據(jù)的插入、刪除、更新和查看等功能。提取數(shù)據(jù)表中的行的語句如下:
DataRow dr = dt.Rows[n];
其中:DataRow代表數(shù)據(jù)行類;dr是數(shù)據(jù)行對(duì)象;dt代表數(shù)據(jù)表對(duì)象; n代表行的序號(hào)(序號(hào)從0開始)。
(2) 數(shù)據(jù)列(DataColumn)
數(shù)據(jù)表中的數(shù)據(jù)列(又稱字段)定義了表的數(shù)據(jù)結(jié)構(gòu),例如,可以用它確定列中的數(shù)據(jù)類型和大小,還可以對(duì)其他屬性進(jìn)行設(shè)置。例如,確定列中的數(shù)據(jù)是否是只讀的、是否是主鍵、是否允許空值等;還可以讓列在一個(gè)初始值的基礎(chǔ)上自動(dòng)增殖,增值的步長還可以自行定義。
 某列的值需要在數(shù)據(jù)行的基礎(chǔ)上進(jìn)行。語句如下:

  1. string dc = dr.Columns['字段名'].ToString();

  或者 

  1. string dc = dr.Column[i].ToString();//i表示對(duì)應(yīng)的列索引

 綜合前面的語句,若想取出數(shù)據(jù)表(dt)中第3條記錄中的“姓名”字段,并將該字段的值放入一輸入框(textBox1)中時(shí),語句可以寫成:

  1. DataRow dRow = dt.Rows[2 ];   // 從數(shù)據(jù)表提取行

  2. string textBox1.Text=dRow['CompanyName'].ToString();  // 從行中取出字段的值

 下面是一個(gè)利用代碼在內(nèi)存中創(chuàng)建表并顯示的例子(仍然是采用了單頁模式):

  1. <%@ Page Language='C#' %>

  2. <%@ Import Namespace='System.Data' %>

  3. <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>

  4. <script runat='server'>

  5.     protected void Page_Load(object sender, EventArgs e)

  6.     {

  7.     }

  8.     private void CreateDataTable()

  9.     {

  10.         //實(shí)例化DataTable

  11.         DataTable data = new DataTable();

  12.         //創(chuàng)建一個(gè)名為'ID'的列,值類型為int

  13.         DataColumn dc1 = new DataColumn('ID', typeof(int));

  14.         dc1.AllowDBNull = false;//不允許為空

  15.         dc1.AutoIncrement = true;//自動(dòng)遞增

  16.         dc1.AutoIncrementSeed = 1;//列起始值為1

  17.         dc1.AutoIncrementStep = 1;//步長為1

  18.         data.Columns.Add(dc1);//添加列到表中

  19.         //創(chuàng)建一個(gè)新列,列名為'UserName',值類型為string

  20.         DataColumn dc = new DataColumn('UserName', typeof(string));

  21.         dc.Unique = true;//設(shè)置唯一索引

  22.         dc.MaxLength = 20;//設(shè)置字段最大長度

  23.         data.Columns.Add(dc);

  24.         dc = new DataColumn('Birthday', typeof(DateTime));

  25.         dc.DefaultValue = DateTime.Now.AddYears(-2000);

  26.         data.Columns.Add(dc);

  27.         DataRow row=data.NewRow();//得到與剛才創(chuàng)建的表有相同結(jié)構(gòu)的行

  28.         row['UserName']='張飛';//設(shè)置列的UserName值,Birthday列采用默認(rèn)值

  29.         data.Rows.Add(row);//添加行

  30.         row = data.NewRow();

  31.         row['UserName'] = '劉備';

  32.         row['Birthday'] = new DateTime(1, 3, 4);

  33.         data.Rows.Add(row);

  34.         row = data.NewRow();

  35.         row['UserName'] = '關(guān)羽';

  36.         row['Birthday'] = new DateTime(6, 11, 7);//跟周公同月同日了:)

  37.         data.Rows.Add(row);

  38.         Session['Data'] = data;//將創(chuàng)建的表和添加的數(shù)據(jù)保存到Session中

  39.     }

  40.     protected void ShowData()

  41.     {

  42.         if (Session['Data'] == null)

  43.         {

  44.             CreateDataTable();

  45.         }

  46.         DataTable data=(DataTable)Session['Data'];

  47.         for (int i = 0; i < data.Rows.Count; i++)

  48.         {

  49.             Response.Write('<tr>');

  50.             Response.Write('<td>' + data.Rows[i]['ID'].ToString() + '</td>');

  51.             Response.Write('<td>' + data.Rows[i]['UserName'].ToString() + '</td>');

  52.             Response.Write('<td>' + DateTime.Parse(data.Rows[i]['Birthday'].ToString()).ToShortDateString() + '</td>');

  53.             Response.Write('</tr>');

  54.         }

  55.     }

  56. </script>

  57. <html xmlns='http://www.w3.org/1999/xhtml' >

  58. <head runat='server'>

  59.     <title>自己創(chuàng)建DataTable的例子</title>

  60. </head>

  61. <body>

  62.     <form id='form1' runat='server'>

  63.     <div>

  64.     <table border='1' width='400'>

  65.     <tr><td>編號(hào)</td><td>用戶名</td><td>生日</td></tr>

  66.     <% ShowData(); %>

  67.     </table>

  68.     </div>

  69.     </form>

  70. </body>

  71. </html>

上面代碼我已經(jīng)做了詳盡的注釋,它的運(yùn)行效果如下:

參數(shù)化SQL語句
在前面的系列文章《asp.net夜話之三:表單和控件》中我提到了SQL注入的問題,避免SQL注入的方法有兩種:一是所有的SQL語句都存放在存儲(chǔ)過程中,這樣不但可以避免SQL注入,還能提高一些性能,并且存儲(chǔ)過程可以由專門的數(shù)據(jù)庫管理員(DBA)編寫和集中管理(這種做法我在一些公司見過),不過這種做法有時(shí)候針對(duì)相同的幾個(gè)表有不同條件的查詢,SQL語句可能不同,這樣就會(huì)編寫大量的存儲(chǔ)過程,所以有人提出了第二種方案:參數(shù)化SQL語句。例如我們?cè)诒酒袆?chuàng)建的表UserInfo中查找所有女性用戶,那么通常情況下我們的SQL語句可能是這樣:

  1. select * from UserInfo where sex=0

在參數(shù)化SQL語句中我們將數(shù)值以參數(shù)化的形式提供,對(duì)于上面的查詢,我們用參數(shù)化SQL語句表示為:

  1. select * from UserInfo where sex=@sex

我們?cè)賹?duì)代碼中對(duì)這個(gè)SQL語句中的參數(shù)進(jìn)行賦值,假如我們要查找UserInfo表中所有年齡大于30歲的男性用戶,這個(gè)參數(shù)化SQL語句可以這么寫:

  1. select * from UserInfo where sex=@sex and age>@age

下面是執(zhí)行這個(gè)查詢并且將查詢結(jié)果集以DataTable的方式返回的代碼:

  1. //實(shí)例化Connection對(duì)象

  2. SqlConnection connection = new SqlConnection('Data Source=(local);Initial Catalog=AspNetStudy;Persist Security Info=True;User ID=sa;Password=sa');

  3. //實(shí)例化Command對(duì)象

  4. SqlCommand command = new SqlCommand('select * from UserInfo where sex=@sex and age>@age', connection);

  5. //第一種添加查詢參數(shù)的例子

  6. command.Parameters.AddWithValue('@sex', true);

  7. //第二種添加查詢參數(shù)的例子

  8. SqlParameter parameter = new SqlParameter('@age', SqlDbType.Int);//注意UserInfo表里age字段是int類型的

  9. parameter.Value = 30;

  10. command.Parameters.Add(parameter);//添加參數(shù)

  11. //實(shí)例化DataAdapter

  12. SqlDataAdapter adapter = new SqlDataAdapter(command);

  13. DataTable data = new DataTable();

上面的代碼是訪問SQL Server數(shù)據(jù)庫的代碼。如果本文中提到的數(shù)據(jù)分別在Access、MySQL、Oracle數(shù)據(jù)庫,那么對(duì)應(yīng)的參數(shù)化SQL語句及參數(shù)分別如下:

數(shù)據(jù)庫AccessMySQLOracle

SQL

語句

select * from UserInfo

where sex=? and age>? 

select * from UserInfo

where sex=?sex and age>?age 

select * from UserInfo

where sex=:sex and age>:age

參數(shù) OleDbParameterMySqlParameterOracleParameter
實(shí)例
化參
數(shù) 
OleDbParameter p=new OleDbParameter(“?”, OleDbType. Boolean); MySqlParameter p=new MySqlParameter(“?sex”, MySqlDbType.Bit); OracleParameter p=new OracleParameter(“:sex”, OracleType.Byte);
 賦值p.Value=true; p.Value=1; p.Value=1;
   

  通過上面的實(shí)例代碼我們可以看出盡管SQL語句大體相似,但是在不同數(shù)據(jù)庫的特點(diǎn),可能參數(shù)化SQL語句不同,例如在Access中參數(shù)化SQL語句是在參數(shù)直接以“?”作為參數(shù)名,在SQL Server中是參數(shù)有“@”前綴,在MySQL中是參數(shù)有“?”前綴,在Oracle中參數(shù)以“:”為前綴。
注意:因?yàn)樵贏ccess中參數(shù)名都是“?”,所以給參數(shù)賦值一定要按照列順序賦值,否則就有可能執(zhí)行出錯(cuò)。

分頁查詢SQL語句
在實(shí)際中我們經(jīng)常遇到表里的記錄數(shù)非常龐大(數(shù)萬至數(shù)百萬),而一次只顯示幾十條數(shù)據(jù)的情況,如果我們直接用下面的SQL語句查詢并填充到DataTable的話,將是一個(gè)非??植赖氖虑?假設(shè)UserInfo有幾百萬用戶數(shù)據(jù)):
Select * from UserInfo
在csdn論壇里我曾經(jīng)就見過有一位朋友一張表里有8萬條左右的記錄,他每次都是將全部數(shù)據(jù)填充到DataTable,然后在循環(huán)中決定顯示哪些數(shù)據(jù),最后他在論壇上求助,說那樣做的效果太慢了,當(dāng)時(shí)把我和其它幾個(gè)回帖的朋友嚇懵了。其實(shí)他這種情況就應(yīng)該用分頁查詢。
分頁查詢就是根據(jù)需要每次只返回所需要的數(shù)據(jù),而不用每次都從數(shù)據(jù)庫中全部把數(shù)據(jù)提取出來,這樣可以降低程序與數(shù)據(jù)庫之間的數(shù)據(jù)傳送量,并且還可以提高程序的性能。
一般來說我們?cè)跀?shù)據(jù)量大的情況下總是會(huì)分頁顯示(誰也不會(huì)一下子將幾萬條數(shù)據(jù)全部一次性顯示給用戶),這樣決定我們返回的查詢結(jié)果集的參數(shù)有兩個(gè):當(dāng)前顯示的頁數(shù)pageIndex和每頁顯示的記錄條數(shù)size。
這里來舉例在SQL Server中我們?nèi)绾螌懛猪摬樵兊腟QL語句,假設(shè)我們按照UserID字段降序查詢,每頁顯示5條記錄。
下面是按照UserID字段降序查詢?nèi)克杏脩舻慕貓D(出于某些原因,我把前面的14條記錄刪除掉了):

 
那么第一頁顯示的應(yīng)該是UserID最小的前5位用戶。查詢第一頁要顯示的用戶信息應(yīng)該是:
 
第一頁我們可以按照對(duì)UserID降序查詢,并利用top 5取出前5條記錄。可是第二頁的SQL語句我們?cè)撛趺磳懩??下面的語句是否正確呢?
select top 10 * from UserInfo order by UserID asc
上面的語句肯定不正確!因?yàn)閠op 10將會(huì)取到前10條記錄,而我們每頁只顯示5條記錄,第二頁顯示的數(shù)據(jù)應(yīng)該是按照UserID降序排列之后第6條到10條記錄,有沒有辦法做到這一點(diǎn)呢?有兩種辦法:第一種就是前面我所提到的一次性將全部數(shù)據(jù)提取并填充到DataTable中,然后在for循環(huán)中通過i從5開始,并且i小于10(因?yàn)樵贑#中所有的集合下標(biāo)都是從0開始的,第六條記錄的下標(biāo)就是5)這種方法顯示5條數(shù)據(jù),但是這種做法的缺點(diǎn)我在前面也提到了。第二種辦法就是在數(shù)據(jù)庫中過濾。我們通過分析發(fā)現(xiàn),第二頁要顯示的記錄的UserID字段有以下特點(diǎn):它們是緊跟這第一頁顯示的記錄之后的5條記錄,也就是通過對(duì)UserID字段進(jìn)行降序排列時(shí),它們是除了第一頁數(shù)據(jù)之后的5條記錄,也就是它們的UserID不在第一頁的UserID之中,在SQL語句有一個(gè)not in這個(gè)正好可以排上用場。
首先我們按照對(duì)UserID進(jìn)行降序排序,查詢出前面第一頁使用的數(shù)據(jù)的UserID,SQL語句及執(zhí)行結(jié)果如下:
 
然后我們?cè)侔凑諏?duì)UserID進(jìn)行降序查詢,并且UserID不在第一頁所使用的數(shù)據(jù)集中,使用的SQL語句及查詢結(jié)果如下:
 
因?yàn)槲覀兊臄?shù)據(jù)UserID是從14開始,所以UserID在14至19的記錄在第一頁顯示,UserID為20至24的記錄在第二頁顯示,UserID為25至29的記錄在第三頁顯示……依此類推,如果每頁顯示5條記錄,那么第n頁顯示的數(shù)據(jù)記錄的公式應(yīng)該是:
select top 5 * from UserInfo where UserId not in
(select top (n-1)*5 UserID from UserInfo order by UserID asc)
order by UserID asc
需要注意的是:上面的查詢,兩次都是對(duì)UserID進(jìn)行排序,并且都是降序,也就是說我們分頁查詢的時(shí)候?qū)戇@種SQL語句的時(shí)候一定要都是對(duì)同一字段進(jìn)行相同方式(asc或desc)的排序查詢,這樣查詢的結(jié)果才會(huì)正確。
還有一點(diǎn),如何查詢數(shù)據(jù)庫滿足條件的記錄條數(shù)呢?
還記得我講過Command對(duì)象的ExecuteScalar()方法吧,這個(gè)方法就是返回查詢結(jié)果的第一行第一列的。
下面是例子:

  1. //實(shí)例化Connection對(duì)象

  2. SqlConnection connection = new SqlConnection('Data Source=(local);Initial Catalog=AspNetStudy;Persist Security Info=True;User ID=sa;Password=sa');

  3. //實(shí)例化Command對(duì)象

  4.  SqlCommand command = new SqlCommand('select count(1) as 男性人數(shù) from UserInfo where sex=1', connection);

  5. //打開Connection對(duì)象

  6.  connection.Open();

  7.  //執(zhí)行SQL語句

  8. //得到第一行第一列的結(jié)果,這里是所有用戶總數(shù)

  9.  int count = int.Parse(command.ExecuteScalar().ToString());

  10.  //關(guān)閉Connection對(duì)象

  11.  connection.Close();

最后一點(diǎn),如果計(jì)算總頁數(shù)的問題。假如我們有20條記錄,每頁顯示5條,毫無疑問總共分4頁顯示。如果是21條記錄呢?答案是分5頁顯示,盡管最后一頁只有一條記錄,但是還是要顯示的。這里也有一個(gè)公式,假如總共有m條記錄,每頁顯示n條記錄(這里m,n都是大于0的整數(shù))那么需要顯示全部記錄所用到的頁數(shù)page為:

  1. page=(m%n)==0?(m/n):(m/n+1);

題外話:今夜的夜話就到這里了,原來計(jì)劃寫一個(gè)數(shù)據(jù)庫訪問通用類的(這個(gè)很多朋友經(jīng)常問到),但是這篇文章的篇幅確實(shí)太長了,足足25頁Word文檔,我怕csdn博客不能放下這個(gè)長的內(nèi)容,如果確實(shí)有人要我再補(bǔ)上。下一篇我將講述數(shù)據(jù)綁定的有關(guān)知識(shí)。ADO.NET和數(shù)據(jù)綁定是.net編程中非常重要的兩部分。下一篇我打算花更長一點(diǎn)的時(shí)間醞釀寫作思路,希望給大家?guī)砀髱椭?br>周公(周金橋)
2008-10-13 01:17

 注意,因?yàn)閭€(gè)人空間大小和下載速度受限,所以以后不再提供從本人主機(jī)上的下載地址,可以到www.verycd.com下載《ASP.NET夜話》的測試版視頻教程。地址是:http://www.verycd.com/topics/2730883/

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
C#數(shù)據(jù)庫操作
14.2.1 ADO.NET
ADO.NET數(shù)據(jù)庫
參數(shù)化SQL語句
MSSQL優(yōu)化之————探索MSSQL執(zhí)行計(jì)劃
ASP.NET簡易教程4
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服