以下代碼闡明了如何使用 sqldataadapter 對象發出可生成 dataset 或 datatable 的命令。它從 sql server northwind 數據庫中檢索一組產品類別。
using system.data;using system.data.sqlclient;public datatable retrieverowswithdatatable(){ using ( sqlconnection conn = new sqlconnection(connectionstring) ) { conn.open(); sqlcommand cmd = new sqlcommand("datretrieveproducts", conn); cmd.commandtype = commandtype.storedprocedure; sqldataadapter adapter = new sqldataadapter( cmd ); datatable datatable = new datatable("products"); adapter .fill(datatable); return datatable; }}1. | 創建一個 sqlcommand 對象以調用該存儲過程,并將其與一個 sqlconnection 對象(顯示)或連接字符串(不顯示)相關聯。 |
2. | 創建一個新的 sqldataadapter 對象并將其與 sqlcommand 對象相關聯。 |
3. | 創建一個 datatable(也可以創建一個 dataset)對象。使用構造函數參數來命名 datatable。 |
4. | 調用 sqldataadapter 對象的 fill 方法,用檢索到的行填充 dataset 或 datatable。 |
以下代碼片段闡明了可檢索多個行的 sqldatareader 方法。
using system.io;using system.data;using system.data.sqlclient;public sqldatareader retrieverowswithdatareader(){ sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=northwind"); sqlcommand cmd = new sqlcommand("datretrieveproducts", conn ); cmd.commandtype = commandtype.storedprocedure; try { conn.open(); // generate the reader. commandbehavior.closeconnection causes the // the connection to be closed when the reader object is closed return( cmd.executereader( commandbehavior.closeconnection ) ); } catch { conn.close(); throw; }}// display the product list using the consoleprivate void displayproducts(){ sqldatareader reader = retrieverowswithdatareader(); try { while (reader.read()) { console.writeline("{0} {1} {2}", reader.getint32(0).tostring(), reader.getstring(1) ); } } finally { reader.close(); // also closes the connection due to the // commandbehavior enum used when generating the reader }}1. | 創建一個用來執行存儲過程的 sqlcommand 對象,并將其與一個 sqlconnection 對象相關聯。 |
2. | 打開連接。 |
3. | 通過調用 sqlcommand 對象的 executereader 方法創建一個 sqldatareader 對象。 |
4. | 要從流中讀取數據,請調用 sqldatareader 對象的 read 方法來檢索行,并使用類型化訪問器方法(如 getint32 和 getstring 方法)來檢索列值。 |
5. | 使用完讀取器后,請調用其 close 方法。 |
可以使用 sqlcommand 對象來生成 xmlreader 對象,后者可提供對 xml 數據的基于流的只進訪問。命令(通常為存儲過程)必須產生基于 xml 的結果集,對于 sql server 2000 而言,該結果集通常包含一個帶有有效 for xml 子句的 select 語句。以下代碼片段闡明了該方法:
public void retrieveanddisplayrowswithxmlreader(){ using( sqlconnection conn = new sqlconnection(connectionstring) ) {; sqlcommand cmd = new sqlcommand("datretrieveproductsxml", conn ); cmd.commandtype = commandtype.storedprocedure;try { conn.open(); xmltextreader xreader = (xmltextreader)cmd.executexmlreader(); while ( xreader.read() ) { if ( xreader.name == "products" ) { string stroutput = xreader.getattribute("productid"); stroutput += " "; stroutput += xreader.getattribute("productname"); console.writeline( stroutput ); } } xreader.close(); // xmltextreader does not support idisposable so it can't be // used within a using keyword }} 上述代碼使用了以下存儲過程:
create procedure datretrieveproductsxmlasselect * from products for xml autogo
1. | 創建一個 sqlcommand 對象來調用可生成 xml 結果集的存儲過程(例如,在 select 語句中使用 for xml 子句)。將該 sqlcommand 對象與某個連接相關聯。 |
2. | 調用 sqlcommand 對象的 executexmlreader 方法,并且將結果分配給只進 xmltextreader 對象。當您不需要對返回的數據進行任何基于 xml 的驗證時,這是應該使用的最快類型的 xmlreader 對象。 |
3. | 使用 xmltextreader 對象的 read 方法來讀取數據。 |
借助于命名的輸出參數,可以調用在單個行內返回檢索到的數據項的存儲過程。以下代碼片段使用存儲過程來檢索 northwind 數據庫的 products 表中包含的特定產品的產品名稱和單價。
void getproductdetails( int productid, out string productname, out decimal unitprice ){ using( sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=northwind") ) { // set up the command object used to execute the stored proc sqlcommand cmd = new sqlcommand( "datgetproductdetailsspoutput", conn ) cmd.commandtype = commandtype.storedprocedure; // establish stored proc parameters. // @productid int input // @productname nvarchar(40) output // @unitprice money output // must explicitly set the direction of output parameters sqlparameter paramprodid = cmd.parameters.add( "@productid", productid ); paramprodid.direction = parameterdirection.input; sqlparameter paramprodname = cmd.parameters.add( "@productname", sqldbtype.varchar, 40 ); paramprodname.direction = parameterdirection.output; sqlparameter paramunitprice = cmd.parameters.add( "@unitprice", sqldbtype.money ); paramunitprice.direction = parameterdirection.output; conn.open(); // use executenonquery to run the command. // although no rows are returned any mapped output parameters // (and potentially return values) are populated cmd.executenonquery( ); // return output parameters from stored proc productname = paramprodname.value.tostring(); unitprice = (decimal)paramunitprice.value; }}1. | 創建一個 sqlcommand 對象并將其與一個 sqlconnection 對象相關聯。 |
2. | 通過調用 sqlcommand 的 parameters 集合的 add 方法來設置存儲過程參數。默認情況下,參數都被假設為輸入參數,因此必須顯式設置任何輸出參數的方向。 注 一種良好的習慣做法是顯式設置所有參數(包括輸入參數)的方向。 |
3. | 打開連接。 |
4. | 調用 sqlcommand 對象的 executenonquery 方法。這將填充輸出參數(并可能填充返回值)。 |
5. | 通過使用 value 屬性,從適當的 sqlparameter 對象中檢索輸出參數。 |
6. | 關閉連接。 |
上述代碼片段調用了以下存儲過程。
create procedure [email protected] int,@productname nvarchar(40) output,@unitprice money outputasselect @productname = productname, @unitprice = unitprice from products where productid = @productidgo
可以使用 sqldatareader 對象來檢索單個行,尤其是可以從返回的數據流中檢索需要的列值。以下代碼片段對此進行了說明。
void getproductdetailsusingreader( int productid, out string productname, out decimal unitprice ){ using( sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=northwind") ) { // set up the command object used to execute the stored proc sqlcommand cmd = new sqlcommand( "datgetproductdetailsreader", conn ); cmd.commandtype = commandtype.storedprocedure; // establish stored proc parameters. // @productid int input sqlparameter paramprodid = cmd.parameters.add( "@productid", productid ); paramprodid.direction = parameterdirection.input; conn.open(); using( sqldatareader reader = cmd.executereader() ) { if( reader.read() ) // advance to the one and only row { // return output parameters from returned data stream productname = reader.getstring(0); unitprice = reader.getdecimal(1); } } }}1. | 建立 sqlcommand 對象。 |
2. | 打開連接。 |
3. | 調用 sqldatareader 對象的 executereader 方法。 |
4. | 通過 sqldatareader 對象的類型化訪問器方法(在這里,為 getstring 和 getdecimal)來檢索輸出參數。 |
上述代碼片段調用了以下存儲過程。
create procedure [email protected] intasselect productname, unitprice from productswhere productid = @productidgo
executescalar 方法專門適用于僅返回單個值的查詢。如果查詢返回多個列和/或行,executescalar 將只返回第一行的第一列。
以下代碼說明了如何查找與特定產品 id 相對應的產品名稱:
void getproductnameexecutescalar( int productid, out string productname ){ using( sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=northwind") ) { sqlcommand cmd = new sqlcommand("lookupproductnamescalar", conn ); cmd.commandtype = commandtype.storedprocedure; cmd.parameters.add("@productid", productid ); conn.open(); productname = (string)cmd.executescalar(); }}1. | 建立一個 sqlcommand 對象來調用存儲過程。 |
2. | 打開連接。 |
3. | 調用 executescalar 方法。注意,該方法返回一個對象類型。它包含檢索到的第一列的值,并且必須轉化為適當的類型。 |
4. | 關閉連接。 |
上述代碼使用了以下存儲過程:
create procedure [email protected] intasselect top 1 productnamefrom productswhere productid = @productidgo
可以使用存儲過程輸出或返回參數來查找單個值。以下代碼闡明了輸出參數的用法:
void getproductnameusingspoutput( int productid, out string productname ){ using( sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=northwind") ) { sqlcommand cmd = new sqlcommand("lookupproductnamespoutput", conn ); cmd.commandtype = commandtype.storedprocedure; sqlparameter paramprodid = cmd.parameters.add("@productid", productid ); paramprodid.direction = parameterdirection.input; sqlparameter parampn = cmd.parameters.add("@productname", sqldbtype.varchar, 40 ); parampn.direction = parameterdirection.output; conn.open(); cmd.executenonquery(); productname = parampn.value.tostring(); }}1. | 建立一個 sqlcommand 對象來調用存儲過程。 |
2. | 通過將 sqlparameters 添加到 sqlcommand 的 parameters 集合中,設置任何輸入參數和單個輸出參數。 |
3. | 打開連接。 |
4. | 調用 sqlcommand 對象的 executenonquery 方法。 |
5. | 關閉連接。 |
6. | 通過使用輸出 sqlparameter 的 value 屬性來檢索輸出值。 |
上述代碼使用了以下存儲過程。
create procedure lookupproductnamespoutput @productid int,@productname nvarchar(40) outputasselect @productname = productnamefrom productswhere productid = @productidgo
以下代碼闡明了如何使用返回值來指明是否存在特定行。從編碼角度來看,這類似于使用存儲過程輸出參數,不同之處在于必須將 sqlparameter 方向顯式設置為 parameterdirection.returnvalue。
bool checkproduct( int productid ){ using( sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=northwind") ) { sqlcommand cmd = new sqlcommand("checkproductsp", conn ); cmd.commandtype = commandtype.storedprocedure; cmd.parameters.add("@productid", productid ); sqlparameter paramret = cmd.parameters.add("@productexists", sqldbtype.int ); paramret.direction = parameterdirection.returnvalue; conn.open(); cmd.executenonquery(); } return (int)paramret.value == 1;}1. | 建立一個 sqlcommand 對象來調用存儲過程。 |
2. | 設置一個輸入參數,該參數含有要訪問的行的主鍵值。 |
3. | 設置單個返回值參數。將一個 sqlparameter 對象添加到 sqlcommand 的 parameters 集合中,并將其方向設置為 parameterdirection.returnvalue。 |
4. | 打開連接。 |
5. | 調用 sqlcommand 對象的 executenonquery 方法。 |
6. | 關閉連接。 |
7. | 通過使用返回值 sqlparameter 的 value 屬性來檢索返回值。 |
上述代碼使用了以下存儲過程。
create procedure checkproductsp @productid intasif exists( select productid from products where productid = @productid ) return 1else return 0go
可以使用 sqldatareader 對象并通過調用命令對象的 executereader 方法來獲取單個輸出值。這要求編寫稍微多一點的代碼,因為必須調用 sqldatareader read 方法,然后通過該讀取器的訪問器方法之一來檢索需要的值。以下代碼闡明了 sqldatareader 對象的用法。
bool checkproductwithreader( int productid ){ using( sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=northwind") ) { sqlcommand cmd = new sqlcommand("checkproductexistswithcount", conn ); cmd.commandtype = commandtype.storedprocedure; cmd.parameters.add("@productid", productid ); cmd.parameters["@productid"].direction = parameterdirection.input; conn.open(); using( sqldatareader reader = cmd.executereader( commandbehavior.singleresult ) ) { if( reader.read() ) { return (reader.getint32(0) > 0); } return false; }}上述代碼采用了以下存儲過程。
create procedure checkproductexistswithcount @productid intasselect count(*) from productswhere productid = @productidgo
以下代碼顯示了如何充分利用 sql server .net 數據提供程序所提供的事務處理支持,通過事務來保護資金轉帳操作。該操作在同一數據庫中的兩個帳戶之間轉移資金。
public void transfermoney( string toaccount, string fromaccount, decimal amount ){ using ( sqlconnection conn = new sqlconnection( "server=(local);integrated security=sspi;database=simplebank" ) ) { sqlcommand cmdcredit = new sqlcommand("credit", conn ); cmdcredit.commandtype = commandtype.storedprocedure; cmdcredit.parameters.add( new sqlparameter("@accountno", toaccount) ); cmdcredit.parameters.add( new sqlparameter("@amount", amount )); sqlcommand cmddebit = new sqlcommand("debit", conn ); cmddebit.commandtype = commandtype.storedprocedure; cmddebit.parameters.add( new sqlparameter("@accountno", fromaccount) ); cmddebit.parameters.add( new sqlparameter("@amount", amount )); conn.open(); // start a new transaction using ( sqltransaction trans = conn.begintransaction() ) { // associate the two command objects with the same transaction cmdcredit.transaction = trans; cmddebit.transaction = trans; try { cmdcredit.executenonquery(); cmddebit.executenonquery(); // both commands (credit and debit) were successful trans.commit(); } catch( exception ex ) { // transaction failed trans.rollback(); // log exception details . . . throw ex; } } }}以下存儲過程闡明了如何在 transact-sql 存儲過程內部執行事務性資金轉帳操作。
create procedure [email protected] char(20),@toaccount char(20),@amount moneyasbegin transaction-- perform debit operationupdate accountsset balance = balance - @amountwhere accountnumber = @fromaccountif @@rowcount = 0begin raiserror('invalid from account number', 11, 1) goto abortenddeclare @balance moneyselect @balance = balance from accountswhere accountnumber = @fromaccountif @balance < 0begin raiserror('insufficient funds', 11, 1) goto abortend-- perform credit operationupdate accounts set balance = balance + @amount where accountnumber = @toaccountif @@rowcount = 0begin raiserror('invalid to account number', 11, 1) goto abortendcommit transactionreturn 0abort: rollback transactiongo該存儲過程使用 begin transaction、commit transaction 和 rollback transaction 語句來手動控制該事務。
以下示例代碼顯示了三個服務性 .net 托管類,這些類經過配置以執行自動事務處理。每個類都使用 transaction 屬性進行了批注,該屬性的值確定是否應該啟動新的事務流,或者該對象是否應該共享其直接調用方的事務流。這些組件協同工作來執行銀行資金轉帳任務。transfer 類被使用 requiresnew 事務屬性進行了配置,而 debit 和 credit 被使用 required 進行了配置。結果,所有這三個對象在運行時都將共享同一事務。
using system;using system.enterpriseservices;[transaction(transactionoption.requiresnew)]public class transfer : servicedcomponent{ [autocomplete] public void transfer( string toaccount, string fromaccount, decimal amount ) { try { // perform the debit operation debit debit = new debit(); debit.debitaccount( fromaccount, amount ); // perform the credit operation credit credit = new credit(); credit.creditaccount( toaccount, amount ); } catch( sqlexception sqlex ) { // handle and log exception details // wrap and propagate the exception throw new transferexception( "transfer failure", sqlex ); } }}[transaction(transactionoption.required)]public class credit : servicedcomponent{ [autocomplete] public void creditaccount( string account, decimal amount ) { try { using( sqlconnection conn = new sqlconnection( "server=(local); integrated security=sspi"; database="simplebank") ) { sqlcommand cmd = new sqlcommand("credit", conn ); cmd.commandtype = commandtype.storedprocedure; cmd.parameters.add( new sqlparameter("@accountno", account) ); cmd.parameters.add( new sqlparameter("@amount", amount )); conn.open(); cmd.executenonquery(); } } }catch( sqlexception sqlex ){ // log exception details here throw; // propagate exception }}[transaction(transactionoption.required)]public class debit : servicedcomponent{ public void debitaccount( string account, decimal amount ) { try { using( sqlconnection conn = new sqlconnection( "server=(local); integrated security=sspi"; database="simplebank") ) { sqlcommand cmd = new sqlcommand("debit", conn ); cmd.commandtype = commandtype.storedprocedure; cmd.parameters.add( new sqlparameter("@accountno", account) ); cmd.parameters.add( new sqlparameter("@amount", amount )); conn.open(); cmd.executenonquery(); } } catch (sqlexception sqlex) { // log exception details here throw; // propagate exception back to caller } }}注冊會員,創建你的web開發資料庫,
新聞熱點
疑難解答
圖片精選