首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

打造 ADO 版 SQL Plus:多資料庫連線、錯誤處理、DML/DQL 統一執行架構

     編輯:關於VC++

專案展示

SQL Plus 介面

支援 Access / Oracle / SQL Server 三大資料庫,介面模仿 Oracle SQL Plus,可執行任意 SQL 並顯示結果集或影響列數。

一、多資料庫連線字串策略

_ConnectionPtr m_pConnTemp;
HRESULT hr;
UpdateData();

// Oracle
CString strConn = _T("Provider=MSDAORA;Data Source=") + m_dbserver
    + _T(";User ID=") + m_username + _T(";Password=") + m_passwd;

// SQL Server
CString strConn = _T("Provider=SQLOLEDB.1;Data Source=") + m_dbserver
    + _T(";Initial Catalog=") + m_initDb
    + _T(";User ID=") + m_username + _T(";PWD=") + m_passwd;

// Access
CString strConn = _T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=") + m_filename;

try {
    hr = m_pConnTemp.CreateInstance(_T("ADODB.Connection"));
    if (SUCCEEDED(hr))
        hr = m_pConnTemp->Open((_bstr_t)strConn, _T(""), _T(""), -1);
    OnOK();
} catch (_com_error e) {
    AfxMessageBox(DisplayAdoError(m_pConnTemp));
}

二、統一錯誤訊息擷取

CString CCommon::DisplayAdoError(_ConnectionPtr m_pConnection) {
    long errorcount = m_pConnection->GetErrors()->GetCount();
    _bstr_t add; CString ErrorMessage, temp;
    for (short i=0; i<errorcount; i++) {
        add = m_pConnection->GetErrors()->GetItem(_variant_t((short)i))->GetDescription();
        temp = (char*)add;
        ErrorMessage += temp;
    }
    return ErrorMessage;
}

遍歷 Errors 集合,串接所有 Description,避免只顯示第一個錯誤。

三、DML (INSERT/UPDATE/DELETE) 影響列數取得

_variant_t fieldCount; VariantInit(&fieldCount);
MainFrame->m_pUserSet = MainFrame->m_commandptr->Execute(&fieldCount, NULL, adCmdUnknown);
if (!MainFrame->m_pUserSet->State) { // State 為 0 表示非 SELECT
    View->ShowResult(fieldCount.lVal); // fieldCount.lVal 即影響列數
}
VariantClear(&fieldCount);

關鍵:Execute 第一個參數 RecordsAffected 為輸出參數,DML 回傳影響列數,DQL 回傳 Recordset。

四、DQL (SELECT) 結果集顯示

listTable.ShowWindow(SW_SHOW);
listTable.DeleteAllItems();
// 清除舊欄位
for (i=0; i<listTable.GetHeaderCtrl()->GetItemCount(); i++)
    listTable.DeleteColumn(0);

int fieldCount = Rsc->Fields->Count;
FieldPtr m_fieldCtl;
for (i=0; i<fieldCount; i++) {
    m_fieldCtl = Rsc->Fields->GetItem(long(i));
    int fieldLength = m_fieldCtl->DefinedSize * 10;
    fieldLength = max(50, min(500, fieldLength));
    fieldLength = max(fieldLength, m_fieldCtl->Name.length() * 12);
    listTable.InsertColumn(i, m_fieldCtl->Name, LVCFMT_LEFT, fieldLength);
}

int nItem = 0; _variant_t varValue; _bstr_t bstrValue;
while (!Rsc->adoEOF) {
    m_fieldCtl = Rsc->Fields->GetItem(long(0));
    varValue = m_fieldCtl->Value;
    if (varValue.vt == VT_NULL) bstrValue = _T(""); // 必須處理 NULL,否則轉換會拋出例外
    else bstrValue = varValue;
    nItem = listTable.InsertItem(0xffff, bstrValue);
    
    for (i=1; i<fieldCount; i++) {
        m_fieldCtl = Rsc->Fields->GetItem(long(i));
        varValue = m_fieldCtl->Value;
        if (varValue.vt == VT_NULL) bstrValue = _T("");
        else bstrValue = varValue;
        listTable.SetItem(nItem, i, 1, bstrValue, NULL, 0, 0, 0);
    }
    Rsc->MoveNext();
}

關鍵細節:

  • 欄位寬度自適應:DefinedSize * 10,限制在 50~500 像素,並確保至少能顯示欄位名
  • VT_NULL 顯式轉空字串,避免 _bstr_t 建構子拋出 _com_error
  • 使用 InsertItem(0xffff, ...) 追加至尾部

五、Command 物件進階用法

// 執行 SQL
_CommandPtr m_pCommand;
m_pCommand.CreateInstance(__uuidof(Command));
m_pCommand->ActiveConnection = m_pConnection;
m_pCommand->CommandText = _T("SELECT * FROM DemoTable");
m_pRecordset = m_pCommand->Execute(NULL, NULL, adCmdText);

// 執行預存程序
m_pCommand->CommandText = _T("DemoProc");
m_pCommand->Execute(NULL, NULL, adCmdStoredProc);
// 如有參數,需用 _ParameterPtr 建立並 Append 至 m_pCommand->Parameters

六、編譯與部署提醒

// Stdafx.h 指定正確路徑
#import "msado15.dll" no_namespace rename("EOF", "adoEOF")
// 若路徑不同,請用完整路徑:C:\Program Files\Common Files\System\ADO\msado15.dll
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved