在VC++中用ODBC訪問SQL Server數據庫

2009-3-6     作者:        編輯:齊瑞瑞   點擊進入論壇
關鍵詞:VC      ODBC  數據庫
ODBC(Open Database Connectivity,開放數據庫連接)是由Microsoft定義的一種數據庫訪問標準,它提供了一種標準的數據庫訪問方法以訪問不同數據庫提供商的數據庫,其本質上是一組數據庫訪問API.雖然數據庫訪問有多種方法,但ODBC以其編程相對簡單,在實際編程中被廣泛使用。

VC++中提供了一組封裝了ODBC API的MFC ODBC類,以減少程序代碼編寫量。在VC++中使用MFC ODBC類訪問數據庫時,一般都是先配置或選擇已有的數據源,再構造CDatabase類對象,打開數據源,用該數據庫類對象和SQL(結構化查詢語言)可以對庫進行訪問,再構造CRecordset類或其繼承類對象,用數據集類對象和SQL可以實現對庫中的表的操作。在VC++中用MFC ODBC類操作SQL Server數據庫基本上也是這個思路。

1.配置數據源

在程序中根據用戶選擇動態配置數據源而不調用ODBC數據源管理器,對於應用程序開發有時是十分必要的。畢竟ODBC數據源管理器對於對數據庫不熟悉的用戶顯的複雜了,且ODBC數據源管理器的界面風格有可能與整個應用程序的界面風格不一致,對於嚴謹的應用程序開發者來說,這些都是不能容忍的。

配置SQL Server數據源時,必須有SQL Server服務器名和服務器中的目標數據庫名(否則打開該數據源時,就會彈出配置數據源對話框或失敗)。這與配置Access等數據庫的數據源時指定數據庫文件的路徑不同。

可以通過ODBC API函數SQLBrowseConnect得到本地所有的SQL Server服務器、服務器中的庫、語言信息等。其使用方法如下所示:

①得到服務器名

SQLBrowseConnect(hdbc, "DRIVER={SQL Server};", SQL_NTS, BrowseResult, sizeof(BrowseResult), &BrowseResultLen);

其中hdbc是用SQLAllocHandle函數得到的連結句柄,第二個參數是指定連結屬性的輸入字符串,第三個參數是輸入字符串的長度,第四個參數是輸出字符串的指針,我們要得到的信息就存於這個字符串中,第五個參數指定輸出字符串的長度,第六個參數是實際返回字符串的長度。BrowseResult所指向的函數返回的字符串中含有形如“SERVER:Server={Server_name1,Server_name2,…}”的字符串,其中Server_name1、Server_name2就是SQL Server服務器名。

②得到庫名

當用戶選定一個服務器之後,可以進一步利用SQLBrowseConnect函數得到服務器中存在的庫或語言信息(如果需要的話)。

SQLBrowseConnect(hdbc,"SERVER=Server_name1;UID=sa;PWD=515578;",SQL_NTS, BrowseResult, sizeof(BrowseResult), &BrowseResultLen);

其中UID和PWD是訪問該服務器的用戶名和密碼。這次BrowseResult所指向的函數返回的字符串中含有形如DATABASE:Database={master,model,…}和LANGUAGE:Language={Arabic, Brazilian, English, …}的字符串,其中master、model爲服務器中的數據庫名。

利用這些得到信息就可以配置SQL Server數據源了:

SQLConfigDataSource(NULL,ODBC_ADD_DSN,"SQL Server","DSN=myDSN/0 SERVER=xhm/0DATABASE=pubs/0/0" ))

作者有幸在網上找到Santosh Rao編寫的CSQLInfoEnumerator類,該類有 EnumerateSQLServers、EnumerateDatabase、EnumerateDatabaseLanguage三個成員函數,其封裝了SQLBrowseConnect函數並進行相應的字符處理,大大簡化了SQLBrowseConnect函數的使用。

2.與數據源建立連接

如果使用ODBC API函數進行連結,函數SQLConnect、SQLDriverConnect和SQLBrowseConnect都可以實現。其中SQLConnect函數用於給定所有參數直接建立與數據源的連接;SQLDriverConnect用於給定了部分連接參數,並彈出數據源瀏覽窗口與用戶交互,獲得足夠的參數後建立與數據源的連接;而SQLBrowseConnect是通過迭代獲取連結參數再進行連接,其使用如前所述。

MFC爲連接數據源提供了一個數據庫類CDatabase,通過它我們可以非常方便地與數據源建立連結:

//m_db是CDatabase的對象

  //m_szUserId,m_szPassword是CString對象,爲訪問數據源的用戶名和密碼

CString str;

str = _T("DSN=xhmtest;UID=")+m_szUserId+_T(";PWD=")+m_szPassword;

if (! m_db.OpenEx(str, CDatabase::noOdbcDialog ) ){

AfxMessageBox("打開數據源失敗");

}

 

另外,如果我們想對數據源進行操作,就可以利用打開的CDatabase對象執行SQL語句實現。如新建一張表:

str = "CREATE TABLE TableDemo (Column1TEXT, Column2 NUMBER)";

m_db.ExecuteSQL(sSql);

3.得到數據庫的結構信息

在VC++中可以單獨利用ODBC API獲取數據庫的結構信息,但方法非常複雜,各種參數也不易理解,且返回的結果不易獲取。MFC中也沒有爲應用程序開發者得到數據庫結構信息而提供單獨的類。但是我們還是可以通過一些已有的方法方便地獲得數據庫的結構信息。

3.1 得到數據庫中的表

利用ODBC API函數SQLTables可以得到數據庫中的表信息,但使用不易。

在MSDN的sample中有一個catalog例程,它示範瞭如果得到一個數據庫的表信息和表中的字段信息,該程序中有兩個非常實用的類:Ctables和Ccolumns.其中CTables繼承CRecordset類,通過非常巧妙的方法封裝了SQLTables函數,並將結果集存於CRecordset類,方便獲取。

在程序中我們可以這樣應用:

//m_db是已經打開的CDatabse對象,

//m_strTableOwner是CComboBox對象

CTables rs(&m_db);

rs.Open(NULL, NULL, NULL, "TABLE");

CString strTableRef;

m_combTable.ResetContent();

while (!rs.IsEOF())

{

strTableRef = _T("[");

if (!rs.m_strTableOwner.IsEmpty())

strTableRef += rs.m_strTableOwner + _T("].[");

strTableRef += rs.m_strTableName + _T("]");

m_combTable.AddString(strTableRef);

rs.MoveNext();

}

rs.Close();

 

在CTables對象Open方法第四個能數指定“TABLE”是指返回庫中的表,當該參數爲“SYSTEM TABLE”時返回系統表,當爲NULL時,返回所有表。

3.2 得到表中字段結構

得到表中字段結構有三種具體實現方式:

①直接利用ODBC API 函數SQLColumn;其實現也同樣複雜。

②利用前面提到的封裝了SQLColumns函數的CColumns類;其使用方法與CTables類似,其成員變量m_strColumnName即爲字段名

③利用CRecordset類的成員函數。MFC在CRecordset類中提供了獲取表結構信息方法,使用非常方便。(但很奇怪爲什麼CDatabase類沒有獲取庫結構信息的類方法?)

我們以利用CRecodrset爲例簡單說明怎樣得到表結構。假設現在要得到用戶在CComboBox對象中所選表的所有字段名,並將它埴入一個CListCtrl對象(其View屬性被設爲Report)的列名中去:

//m_strTableOwner和上同,爲CComboBox對象

//m_listData爲ClistCtrl對象

CRecordset rs

CODBCFieldInfo info;

CString strSQL;

m_combTable.GetLBText(m_combTable.GetCurSel(), strSQL);

strSQL = _T("SELECT * FROM ") + strSQL;

rs.Open(Open(CRecordset::snapshot, strSQL, CRecordset::readOnly);

int nColumns = rs.GetODBCFieldCount();

for (int nNum = 0; nNum < nColumns; nNum++)

{

prs->GetODBCFieldInfo(nNum, info);

m_listData.InsertColumn(nNum, info.m_strName, LVCFMT_LEFT, 80)

}

 

另外,我們可以利用CRecordSet::GetFieldValue函數通過指定列名或列序數得到記錄集中游標所指記錄的值,通過CRecordset::AddNew、CRecordset::CancelUpdate、CRecordset::Delete、CRecordset::Edit、CRecordset::Update等函數操作CRecordset打開的表。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章