国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

ADO.NET詳細研究(五)--DataReader終結篇

2024-07-10 13:05:19
字體:
來源:轉載
供稿:網友
中國最大的web開發資源網站及技術社區,
這一次我們將把datareader了結,同時我們提到的有些技巧與datareader無關但是是很基本的也很有用的技巧。
一,參數化查詢
在上一篇文章發表以后不少網友提意見說代碼不規范,沒有對sql使用參數,這確實是很大一個漏洞,所以我在這里首先談一下參數化查詢問題。
使用參數化查詢的好處:可以防止sql注入式攻擊,提高程序執行效率。
針對sql server .net data provider,我們可以使用@作為前綴標記的參數。比如:
const string connstr = "data source=bineon;user=sa;password=test;initial catalog=northwind;";
string sql = "select productid,productname from products";
sql += " where categoryid = @categoryid and productid < @categoryid ";
sqlconnection conn = new sqlconnection(connstr);
sqlcommand cmd = new sqlcommand(sql,conn);
cmd.parameters.add("@categoryid",categoryidvalue);
cmd.parameters.add("@maxproductid",maxproductidvalue);
conn.open();
sqldatareader reader = cmd.executereader();
上面的代碼段在定義sql語句的時候使用了兩個參數@categoryid和@categoryid。為了是參數在執行過程中獲得具體值,我們使用prarmeter對象,通過它把參數添加到command對象上,這樣就獲得參數化查詢。
當然上面使用的add方法有其他重載版本,比如我們可以自己定義parameter對象然后再添加:
sqlparameter para = new sqlparameter("@categoryid",categoryidvalue);
cmd.parameters.add(para);
上面sqlparameter的構造函數也有多個重載版本。具體可以查看msdn。
注意:上面的參數必須使用@前綴,另外也不僅僅是查詢才能使用參數,其他更新數據庫的操作類似的都能采用參數。
上面我們給出了針對sql server參數化查詢的方法,現在我們討論在oledb 和odbc中指定參數。
其實這兩種provider都不支持指定參數的方法,但是我們可以在查詢中使用(?)作為占位符,去指定參數將出現的位置。
sql = "select productid,productname from products";
sql += " where categoryid =? and productid < ?";
接下來我們同樣應該把parameter對象添加到command的parameters集合里面,但是這個時候注意參數添加的順序必須和你使用?的順序相通,這個是與上面sql server .net data provider不同的地方。
oledbcommand cmd = new oledbcommand(sql,conn);
cmd.parameters.add(“catid”,categoryidvalue);
cmd.parameters.add(“maxproductid”,maxproductidvalue);
如果上面添加參數的次序弄反了,那么maxproductidvalue將被指定到第一個?那里,那么就出錯了。另外上面的參數名catid和maxproductid無所謂,你怎么命名都可以,甚至是空串也行。
注意:上面參數名無所謂,但是添加參數的次序很重要,不能顛倒。同樣的其他更新數據庫的操作也支持(?)占位符。

二,使用輸出參數檢索數據
這種方法的前提是使用存儲過程。其實對支持存儲過程的dbms比如sql server來說,其上的所有操作都應該使用存儲過程,以獲得更好的執行效率。
比如我現在需要在我的聯系人數據庫中找出一個和指定id相同的聯系人的姓名(關于聯系人數據庫請看我的上一篇文章),我應該怎么做呢?一個辦法是使用datareader,但是效率如何?另外也許我們可以選擇更好的executescalar(),但是如果我想知道的是聯系人的姓名和電話呢?executescalar()的效率確實比datareader好,但是它只能返回單個值,這個時候它也不能滿足要求。我們這里使用存儲過程輸出參數來解決這個問題。存儲過程如下:
create procedure getinfo
(
@fid int,
@fname varchar(8) output,
@fphone varchar(12) output
)
as
select @fname = fname,@fphone = fphone
from friend
where fid = @fid
go
上面的關鍵字output指明參數是輸出參數。
然后我們編寫代碼:
sqlconnection conn = new sqlconnection(connstr);
sqlcommand cmd = conn.createcommand();
cmd.commandtext = "getinfo";
cmd.commandtype = commandtype.storedprocedure;
上面的代碼新建conn對象和cmd對象,并把cmd對象的執行命令指定為名為getinfo的存儲過程。接下來我們需要給cmd對象的parameters集合添加parameter對象了。
sqlparameter param = cmd.parameters.add("@fid",16);
param = cmd.parameters.add("@fname",sqldbtype.varchar,8);
param.direction = parameterdirection.output;
param = cmd.parameters.add("@fphone",sqldbtype.varchar,8);
param.direction = parameterdirection.output;
我們注意到了上面的@fname和@fphone參數添加的時候指定了參數為輸出方向,這個就是和存儲過程里面的參數方向是一致的。下面我們執行命令同時獲得對應的值。
conn.open();
cmd.executenonquery();
string fname = cmd.parameters["@fname"].value.tostring();
string fphone = cmd.parameters["@fphone"].value.tostring();
conn.close();
三,檢索多個無關的結果集
有時候我們需要對不同的表(也可能是相同的表,但是查詢內容不同)進行無關的查詢,比如我想查看所有聯系人的姓名,然后在查看所有聯系人的住址。當然這個需要我們完全可以一個sql語句搞定,也不需要所謂的多個記錄集,但是請允許我以這個需求來演示多個記錄集的操作。
多個查詢語句之間使用;分開。具體代碼如下:
sqlconnection conn = new sqlconnection(connstr);
sqlcommand cmd = conn.createcommand();
string sqla = "select fname from friend";
string sqlb = "select fphone from friend";
cmd.commandtext = sqla + ";" + sqlb;
然后我們可以和以往一樣獲得datareader,但是由于是多個記錄集,我們讀取完第一個記錄集以后如果使用下一個記錄集呢?答案是nextresult()方法,該方法為bool類型,如果有下一個記錄集就返回真,否則為假。
conn.open();
sqldatareader reader= cmd.executereader();
int i = 1;
do
{
console.writeline("第" + i.tostring() + "個記錄集內容如下:/n");
while(reader.read())
{
console.writeline(reader[0].tostring() + "/t");
}
i++;
}while(reader.nextresult());
注意:由于datareader本身向前只讀的特性,您不能比較多個記錄集的內容,也不能在多個記錄集中來回移動。結果為多個結果集時,數據讀取器定位在第一個記錄集上,這個和數據讀取器的read()方法不同(該方法默認在記錄集之前)。
另外這個例子僅僅時演示多個無關記錄集的使用方法,所以請不要追究例子的實際意義。另外當我們需要檢索相關的記錄信息時,多表連接查詢也是一個很好的選擇,也就是使用sql join查詢。
四,其他相關技術
檢索二進制數據
檢索二進制數據的時候我們必須把commandbehavior.sequentialaccess枚舉值傳遞給executereader方法。另外就是要注意從 記錄集讀取信息的時候必須按照你的sql語句的順序讀取。比如:
sql = “select pub_id,pr_info,logo from pub_info where pub_id=’0763’ “;
那么你讀取的時候必須先取得pub_id,然后才是pr_info,再接著時logo,如果你讀取了pr_info以后又想讀取pub_info,這時你將得到異常。另外需要注意的是讀取大量二進制數據的時候比較好的辦法是使用getbytes方法。下面的代碼演示如果讀取logo的二進制數據。
system.io.memorystream stream = new system.io.memorystream();
system.io.binarywriter writer = new system.io.binarywriter(stream);
int buffersize = 1024;
byte[] buffer = new byte[buffersize];
long offset = 0;
long bytesread = 0;
do
{
bytesread = reader.getbytes(2,offset,buffer,0,buffersize);
writer.writer(buffer,0,(int)bytesread);
writer.flush();
offset += bytesread;
}
while(bytesread == buffersize);
其中getbytes方法參數比較多,具體請參見msdn:
ms-help://ms.msdnqtr.2003feb.2052/cpref/html/frlrfsystemdatasqlclientsqldatareaderclassgetbytestopic.htm
檢索模式信息
如果我們只想取得數據庫表的模式信息,怎么辦?datareader的getschematable方法可以滿足我們的要求。
string sql = "select fid,fname,fphone from friend";
cmd.commandtext = sql;
conn.open();
sqldatareader reader = cmd.executereader();
datatable schematable = reader.getschematable();
然后我們可以遍歷datatable獲得所有模式信息
datarowcollection schemacolumns = schematable.rows;
datacolumncollection schemaprops = schematable.columns;
foreach(datarow schemacolumn in schemacolumns)
{
foreach(datacolumn schemacolumnprop in schemaprops)
{
console.writeline(schemacolumnprop.columnname + "=" + schemacolumn[schemacolumnprop.columnname].tostring());
}
}
但是上面的效率不高,因為我們不需要讀取數據集,但是程序實際上做了這個工作。一個可行的解決辦法是把commandbehavior.schemaonly枚舉傳遞給executerader方法,另外的辦法就是構造特殊的sql命令,比如:
sql = “select fid,fname,fphone from friend where fid = 0”

datareader的功能基本上就介紹完了,如果需要更詳細的資料請查看msdn。下一次我們將討論dataset的簡單功能。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鄂托克旗| 灌阳县| 莒南县| 兰溪市| 石狮市| 南京市| 普兰店市| 江华| 沧州市| 禄丰县| 蒙自县| 泽州县| 察隅县| 曲沃县| 平乐县| 北流市| 繁昌县| 达拉特旗| 铜鼓县| 洛宁县| 元氏县| 辉南县| 北安市| 平江县| 工布江达县| 新巴尔虎右旗| 襄樊市| 大理市| 宁远县| 柘城县| 贵州省| 延庆县| 尼玛县| 新密市| 福清市| 共和县| 滕州市| 鸡西市| 静安区| 克什克腾旗| 玉屏|