文章編號: 310071 - 上次校閱: 2003年10月31日 - 版次: 3.2

如何: 使用 ADO.NET 和 Visual C++.NET 呼叫參數化的預存程序

系統提示本文適用於您使用的作業系統之外的作業系統。與您不相關的文章內容已停用。

在此頁中

全部展開 | 全部摺疊

結論

有幾種方式可以使用 ADO.NET 來呼叫預存程序,並取回傳回值和輸出參數包括:
  • 蒐集傳回的資料列,並使用這些資料列中,除了傳回值和輸出參數,請使用 資料配接器資料集 物件。
  • 使用 DataReader 物件來蒐集傳回的列的這些資料列中移動和來蒐集傳回值和輸出參數。
  • 使用 ExecuteScalar 方法來從第一欄的結果的第一列以傳回值和輸出參數傳回值。這是與彙總函數最有用的。
  • 使用 ExecuteNonQuery 方法以傳回輸出參數和傳回值。任何傳回的資料列會被捨棄。這是執行動作查詢的最有用的。
本文將示範最後三個方法,並使用 SqlCommandOleDbCommand 物件。請確定您正在使用之 Managed 提供者複製程式碼。如果您不確定應該使用哪一個受管理提供者,請造訪下列 Microsoft 開發 o 人 h 員 ? 工 u 具 ? 網路 Web 網站]:
.NET 資料提供者
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconadonetproviders.asp (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconadonetproviders.asp)
在每一個本文中範例參數會新增至 命令 物件的 參數 集合。SQL Server.NET 資料提供者 (SqlClient) 支援具名的參數。因此,當您使用 [SqlCommand 物件您執行一項無法有新增參數任何特定順序但是參數都必須有正確的名稱。在這種情況下您必須新增 at 符號 (@) 參數名稱的前置詞。

或者,OLE DB.NET 資料提供者不支援具名的參數。因此,當您使用 [OleDbCommand 物件時您必須新增參數以正確的順序 (也就是在後端預存程序定義相同的順序)。在這種情況下您不需要將 「 @ 」 前置詞加入至參數的名稱,而且參數名稱不一定要符合那些在預存程序定義。

使用 DataReader 傳回資料列和參數

您可以使用 DataReader 物件來傳回資料的唯讀且順向的資料流。DataReader 包含的資訊可以來自預存程序。這個範例使用 DataReader 物件執行預存程序,有的輸入和輸出參數並再傳回的記錄之間移動,以檢視傳回的參數。
  1. Pubs 範例資料庫中建立下列的預存程序正在執行 Microsoft SQL Server 的電腦上:
    Create Procedure TestProcedure
        (
            @au_idIN varchar (11),
            @numTitlesOUT Integer OUTPUT
        )
    As
    
    select A.au_fname, A.au_lname, T.title 
    from authors as A join titleauthor as TA on
    A.au_id=TA.au_id
    join titles as T
    on T.title_id=TA.title_id
    where A.au_id=@au_idIN
    set @numTitlesOUT = @@Rowcount
    return (5) 
    					
  2. 啟動 Microsoft Visual Studio.NET,並在 Visual C++.NET 中建立新的受管理的 C + + 應用程式專案。
  3. 在 [方案總管] 中按兩下來源 (.cpp) 檔案。
  4. 來源] 檔案中取代下列程式碼中的預設程式碼:

    SQL 用戶端

    附註您必須變更使用者識別碼 <username>值和密碼 = < 強式密碼 > 的值,以正確的值,才能執行這個程式碼。請確定使用者識別碼有適當的權限,才能執行這項作業在資料庫上。
    #include "stdafx.h"
    #using <mscorlib.dll>
    #include <tchar.h>
    #using <system.dll>
    using namespace System;
    #using <system.data.dll>
    using namespace System::Data;
    using namespace System::Data::SqlClient;
    
    // This is the entry point for this application.
    int _tmain(void)
    {
        try{
            SqlConnection *myCon = new SqlConnection("Data Source=mySQLServer;User ID=<username>;
                                                      Password=<strong password>;initial catalog=pubs;");
            myCon->Open();
            
            SqlCommand *myCmd = new SqlCommand("TestProcedure", myCon);
            myCmd->CommandType = CommandType::StoredProcedure;
                    
            // Parameter order does not matter because SqlClient supports named 
            // parameters. Type the exact parameter names as declared in the
            // stored procedure definition at the backend.
            // Parameters should be prefixed with @.
            myCmd->Parameters->Add("@au_idIN",SqlDbType::VarChar,11);
            myCmd->Parameters->get_Item(0)->Value=S"213-46-8915";
    		
            SqlParameter *retParam;
            retParam=myCmd->Parameters->Add("RetVal",SqlDbType::Int,4);
            retParam->Direction=ParameterDirection::ReturnValue;
    
            SqlParameter *outParam;
            outParam=myCmd->Parameters->Add("@numTitlesOUT",SqlDbType::Int,4);
            outParam->Direction=ParameterDirection::Output;
    	
            SqlDataReader *myReader;	
            myReader=myCmd->ExecuteReader();
    	
            while(myReader->Read())
            {
                for(int col=0;col<myReader->FieldCount;col++)
                {
                    Console::Write("{0}: {1}",(myReader->GetName(col))->ToString(),
                                              (myReader->GetValue(col))->ToString());
                    Console::WriteLine();
                }
                    Console::WriteLine();
            }
            myReader->Close();
            Console::WriteLine("Output Param:{0}; Return Value:{1}",
                                outParam->Value,retParam->Value);
            myCon->Close();
        }
        catch(SqlException *mySqlEx)
        {	
            for(int i=0;i<mySqlEx->Errors->Count;i++)
            {
                Console::WriteLine("Source={0};Message={1};",mySqlEx->Errors->
                                   Item[i]->Source,mySqlEx->Errors->Item[i]->Message);
            }
        }
        catch(System::Exception *ex)
        {
            Console::WriteLine(ex->get_Message());
        }
    }
    					

    OLE DB 資料提供者

    #include "stdafx.h"
    #using <mscorlib.dll>
    #include <tchar.h>
    #using <system.dll>
    using namespace System;
    #using <system.data.dll>
    using namespace System::Data;
    using namespace System::Data::OleDb;
    
    // This is the entry point for this application.
    int _tmain(void)
    {
        try{
            OleDbConnection *myCon = new OleDbConnection("Provider=SQLOLEDB.1;
                                                          Data Source=mySQLServer;User ID=<username>;
                                                          Password=<strong password>;initial catalog=pubs;");
            myCon->Open();
            
            OleDbCommand *myCmd = new OleDbCommand("TestProcedure", myCon);
            myCmd->CommandType = CommandType::StoredProcedure;
    
            // The following notation also works. To test this notation,
            // comment out the above two lines, and uncomment the next two lines.
            // OleDbCommand *myCmd = new OleDbCommand("{?=call TestProcedure(?,?)}", myCon);
            // myCmd->CommandType = CommandType::Text;
    
    
            // The parameter order is important in this sample. Parameters are
            // matched with stored procedure parameters in the order they are supplied.
            // Names can be anything. You do not have to prefix them with "@".
            OleDbParameter* retParam=myCmd->Parameters->Add("RetVal",OleDbType::Integer,4);
            retParam->Direction=ParameterDirection::ReturnValue;
    
            myCmd->Parameters->Add("au_idIN",OleDbType::VarChar,11);
            myCmd->Parameters->Item[1]->Value=S"213-46-8915";
    
            OleDbParameter *outParam=myCmd->Parameters->Add("numTitlesOUT",OleDbType::Integer,4);
            outParam->Direction=ParameterDirection::Output;
    	
            OleDbDataReader *myReader;	
            myReader=myCmd->ExecuteReader();
    	
            int rowCnt=0;
    	
            while(myReader->Read())
            {
                for(int col=0;col<myReader->FieldCount;col++)
                {
                    Console::Write("{0}: {1}",(myReader->GetName(col))->ToString(),
                                              (myReader->GetValue(col))->ToString());
                    Console::WriteLine();
                }
             			
                Console::WriteLine();
                rowCnt++;
            }
    
            myReader->Close();
            Console::WriteLine("Output Param:{0}; Return Value:{1}",outParam->
                                Value,retParam->Value);
            myCon->Close();
        }
        catch(OleDbException *mySqlEx)
        {
            for(int i=0;i<mySqlEx->Errors->Count;i++)
            {
                Console::WriteLine("Source={0};Message={1};",mySqlEx->Errors->
                                    Item[i]->Source,mySqlEx->Errors->Item[i]->Message);
            }
        }
        catch(System::Exception *ex)
        {
            Console::WriteLine(ex->get_Message());
        }
    }
    					
  5. 修改連接字串以指向執行 SQL 的電腦 連線 物件的伺服器。
  6. 按 CTRL + F5 按鍵組合,若要編譯並執行專案。[輸出] 視窗會顯示兩個書籍標題、 5 和輸出參數包含 (2) 的記錄數目的傳回值。 請注意您必須關閉 DataReader 程式碼中若要查看參數值。此外,請注意您不需關閉 DataReader 傳回參數之間的所有記錄都移動。

使用命令物件 ExecuteScalar 方法

您可以使用的 命令 物件 ExecuteScalar 方法來擷取參數值。此外,ExecuteScalar 傳回預存程序的第一列的第一個資料行。這是為下列範例中的聚合函數最有用的。
  1. 在執行 SQL Server 的電腦上建立下列預存程序:
    Create Procedure TestProcedure2
        (
            @au_idIN varchar (11)
        )
    As
    select count (T.title) 
    from authors as A join titleauthor as TA on
    A.au_id=TA.au_id
    join titles as T
    on T.title_id=TA.title_id
    where A.au_id=@au_idIN
    Return(5)
    					
  2. 啟動 Visual 的 Studio.NET,然後建立新的 Managed C + + 中 Visual C++.NET 的應用程式專案。
  3. 在 [方案總管] 中按兩下來源 (.cpp) 檔案。
  4. 來源] 檔案中取代下列程式碼中的預設程式碼:

    SQL 用戶端

    附註您必須變更使用者識別碼 <username>值和密碼 = < 強式密碼 > 的值,以正確的值,才能執行這個程式碼。請確定使用者識別碼有適當的權限,才能執行這項作業在資料庫上。
    #include "stdafx.h"
    #using <mscorlib.dll>
    #include <tchar.h>
    #using <system.dll>
    using namespace System;
    #using <system.data.dll>
    using namespace System::Data;
    using namespace System::Data::SqlClient;
    // This is the entry point for this application.
    int _tmain(void)
    {
    
        try{
            SqlConnection *myCon = new SqlConnection("Data Source=mySQLServer;User ID=<username>;
                                                      Password=<strong password>;initial catalog=pubs;");
            myCon->Open();
            
            SqlCommand *myCmd = new SqlCommand("TestProcedure2", myCon);
            myCmd->CommandType = CommandType::StoredProcedure;
    
            SqlParameter* retParam=myCmd->Parameters->Add("RetVal",SqlDbType::Int,4);
            retParam->Direction=ParameterDirection::ReturnValue;
    
            myCmd->Parameters->Add("@au_idIN",SqlDbType::VarChar,11);
            myCmd->Parameters->Item[1]->Value=S"213-46-8915";
    	
            String *cnt;
            cnt=myCmd->ExecuteScalar()->ToString();
            Console::WriteLine("Cnt:{0}; Return Value:{1}",cnt,retParam->Value);
    
            myCon->Close();
    
        }
        catch(SqlException *mySqlEx)
        {
            for(int i=0;i<mySqlEx->Errors->Count;i++)
            {
                Console::WriteLine("Source={0};Message={1};",mySqlEx->Errors->
                                    Item[i]->Source,mySqlEx->Errors->Item[i]->Message);
            }
        }
        catch(System::Exception *ex)
        {
            Console::WriteLine(ex->get_Message());
        }
    
    }
    					

    OLE DB 資料提供者

    #include "stdafx.h"
    #using <mscorlib.dll>
    #include <tchar.h>
    #using <system.dll>
    using namespace System;
    #using <system.data.dll>
    using namespace System::Data;
    using namespace System::Data::OleDb;
    
    // This is the entry point for this application.
    int _tmain(void)
    {
        try{
            OleDbConnection *myCon = new OleDbConnection("Provider=SQLOLEDB.1;
                                                          Data Source=mySQLServer;User ID=<username>;
                                                          Password=<strong password>;initial catalog=pubs;");
            myCon->Open();
            
            OleDbCommand *myCmd = new OleDbCommand("{?=call TestProcedure2(?)}", myCon);
            myCmd->CommandType = CommandType::Text;
    
            OleDbParameter * retParam=myCmd->Parameters->Add("RetVal",OleDbType::Integer,4);
            retParam->Direction=ParameterDirection::ReturnValue;
    
            myCmd->Parameters->Add("au_idIN",OleDbType::VarChar,11);
            myCmd->Parameters->Item[1]->Value=S"213-46-8915";
    	
            String *cnt;
            cnt=myCmd->ExecuteScalar()->ToString();
            Console::WriteLine("Count:{0}; Return Value:{1}",cnt,retParam->Value);
    
            myCon->Close();
        
        }
        catch(OleDbException *mySqlEx)
        {
            for(int i=0;i<mySqlEx->Errors->Count;i++)
            {
                Console::WriteLine("Source={0};Message={1};",mySqlEx->Errors->
                                    Item[i]->Source,mySqlEx->Errors->Item[i]->Message);
            }
        }
        catch(System::Exception *ex)
        {
            Console::WriteLine(ex->get_Message());
        }
    
    }	
    					
  5. 修改連接字串以指向執行 SQL 的電腦 連線 物件的伺服器。
  6. 按下 CTRL + F5 編譯和執行專案。[輸出] 視窗顯示的第一欄的第一列 (計數) 值以及傳回值。

使用命令物件 ExecuteNonQuery 方法

這個範例使用 ExecuteNonQuery 方法以執行查詢,並傳回參數值。ExecuteNonQuery 也傳回查詢執行後會受到影響的記錄數目。不過,ExecuteNonQuery 不會傳回任何資料列或資料行從預存程序。

如果您只需要知道變更多少資料列,您會使用 INSERT、 UPDATE 或 DELETE 陳述式 ExecuteNonQuery 方法是最有用的。在您在此使用一個 SELECT 陳述式預存程序,您收到-1,因為沒有任何資料列受到查詢。
  1. 在執行 SQL Server 的電腦上建立下列預存程序:
    Create Procedure TestProcedure3
        (
            @au_idIN varchar (11),
            @au_fnam varchar (30)
        )
    
    As
    Update authors set au_fname = @au_fnam
    where au_id = @au_idin	
    return (5)
    					
  2. 啟動 Visual 的 Studio.NET,然後建立新的 Managed C + + 中 Visual C++.NET 的應用程式專案。
  3. 在 [方案總管] 中按兩下來源 (.cpp) 檔案。
  4. 來源] 檔案中取代下列程式碼中的預設程式碼:

    SQL 用戶端

    附註您必須變更使用者識別碼 <username>值和密碼 = < 強式密碼 > 的值,以正確的值,才能執行這個程式碼。請確定使用者識別碼有適當的權限,才能執行這項作業在資料庫上。
    #include "stdafx.h"
    #using <mscorlib.dll>
    #include <tchar.h>
    #using <system.dll>
    using namespace System;
    #using <system.data.dll>
    using namespace System::Data;
    using namespace System::Data::SqlClient;
    // This is the entry point for this application.
    int _tmain(void)
    {
        try{
            SqlConnection *myCon = new SqlConnection("Data Source=mySQLServer;User ID=<username>;
                                                      Password=<strong password>;initial catalog=pubs;");
            myCon->Open();
            
            SqlCommand *myCmd = new SqlCommand("TestProcedure3", myCon);
            myCmd->CommandType = CommandType::StoredProcedure;
    
            SqlParameter* retParam=myCmd->Parameters->Add("RetVal",SqlDbType::Int,4);
            retParam->Direction=ParameterDirection::ReturnValue;
    
            myCmd->Parameters->Add("@au_idIN",SqlDbType::VarChar,11);
            myCmd->Parameters->Item[1]->Value=S"213-46-8915";
    
            myCmd->Parameters->Add("@au_fnam",SqlDbType::VarChar,30);
            myCmd->Parameters->Item[2]->Value=S"Marjorie";
    
            int cnt;
            cnt=myCmd->ExecuteNonQuery();
            Console::WriteLine("Number of rows affected:{0}; Return Value:{1}",
                                cnt.ToString(),retParam->Value);
    
            myCon->Close();
    
        }
        catch(SqlException *mySqlEx)
        {
            for(int i=0;i<mySqlEx->Errors->Count;i++)
            {
                Console::WriteLine("Source={0};Message={1};",mySqlEx->Errors->
                        Item[i]->Source,mySqlEx->Errors->Item[i]->Message);
            }
        }
        catch(System::Exception *ex)
        {
            Console::WriteLine(ex->get_Message());
        }
    }
    					

    OLE DB 資料提供者

    #include "stdafx.h"
    #using <mscorlib.dll>
    #include <tchar.h>
    #using <system.dll>
    using namespace System;
    #using <system.data.dll>
    using namespace System::Data;
    using namespace System::Data::OleDb;
    
    // This is the entry point for this application.
    int _tmain(void)
    {
        try{
            OleDbConnection *myCon = new OleDbConnection("Provider=SQLOLEDB.1;
                                                          Data Source=mySQLServer;User ID=<username>;
                                                          Password=<strong password>;initial catalog=pubs;");
            myCon->Open();
            
            OleDbCommand *myCmd = new OleDbCommand("{?=call TestProcedure3(?,?)}", myCon);
            myCmd->CommandType = CommandType::Text;
    
            OleDbParameter *retParam=myCmd->Parameters->Add("RetVal",OleDbType::Integer,4);
            retParam->Direction=ParameterDirection::ReturnValue;
    
            myCmd->Parameters->Add("au_idIN",OleDbType::VarChar,11);
            myCmd->Parameters->Item[1]->Value=S"213-46-8915";
    			
            myCmd->Parameters->Add("au_fnam",OleDbType::VarChar,30);
            myCmd->Parameters->Item[2]->Value=S"Marjorie";
    	
            int cnt;
            cnt=myCmd->ExecuteNonQuery();
            Console::WriteLine("Number of rows affected:{0}; Return Value:{1}",
                                cnt.ToString(),retParam->Value);
    
            myCon->Close();
    
        }
        catch(OleDbException *mySqlEx)
        {
            for(int i=0;i<mySqlEx->Errors->Count;i++)
            {
                Console::WriteLine("Source={0};Message={1};",mySqlEx->Errors->
                                    Item[i]->Source,mySqlEx->Errors->Item[i]->Message);
            }
        }
        catch(System::Exception *ex)
        {
            Console::WriteLine(ex->get_Message());
        }
    
    }	 
    					
  5. 修改連接字串以指向執行 SQL 的電腦 連線 物件的伺服器。
  6. 按下 CTRL + F5 編譯和執行專案。[輸出] 視窗會顯示的是受影響 (intRowAffected) 的資料列數和傳回參數的值。

?考

如需詳細資訊請造訪下列 MSDN 網站:
.NET Framework 類別庫的簡介
http://msdn.microsoft.com/en-us/library/hfa3fa08.aspx (http://msdn.microsoft.com/en-us/library/hfa3fa08.aspx)

擷取使用 [DataReader 的資料
http://msdn.microsoft.com/en-us/library/haa3afyz.aspx (http://msdn.microsoft.com/en-us/library/haa3afyz.aspx)

這篇文章中的資訊適用於:
  • Microsoft ADO.NET (included with the .NET Framework)
  • Microsoft ADO.NET 1.1
  • Microsoft Visual C++ .NET 2002 Standard Edition
  • Microsoft Visual C++ .NET 2003 Standard Edition
關鍵字:?
kbmt kbhowtomaster kbsqlclient kbsystemdata KB310071 KbMtzh
機器翻譯機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:310071? (http://support.microsoft.com/kb/310071/en-us/ )
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。