class CCustomRs : public CADORecordBinding { BEGIN_ADO_BINDING(CCustomRs) ADO_VARIABLE_LENGTH_ENTRY2(3, adVarChar, m_szau_fname, sizeof(m_szau_fname), lau_fnameStatus, false) ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_szau_lname, sizeof(m_szau_lname), lau_lnameStatus, false) ADO_VARIABLE_LENGTH_ENTRY2(4, adVarChar, m_szphone, sizeof(m_szphone), lphoneStatus, true) END_ADO_BINDING() public: CHAR m_szau_fname[22]; ULONG lau_fnameStatus; CHAR m_szau_lname[42]; ULONG lau_lnameStatus; CHAR m_szphone[14]; ULONG lphoneStatus; }; |
class CADORecordBinding { public: STDMETHOD_(const ADO_BINDING_ENTRY*, GetADOBindingEntries) (VOID) PURE; }; BEGIN_ADO_BINDING宏的定义也在icrsint.h文g里,内容是: #define BEGIN_ADO_BINDING(cls) public: \ typedef cls ADORowClass; \ const ADO_BINDING_ENTRY* STDMETHODCALLTYPE GetADOBindingEntries() { \ static const ADO_BINDING_ENTRY rgADOBindingEntries[] = { ADO_VARIABLE_LENGTH_ENTRY2宏的定义也在icrsint.h文g里: #define ADO_VARIABLE_LENGTH_ENTRY2(Ordinal, DataType, Buffer, Size, Status, Modify)\ {Ordinal, \ DataType, \ 0, \ 0, \ Size, \ offsetof(ADORowClass, Buffer), \ offsetof(ADORowClass, Status), \ 0, \ classoffset(CADORecordBinding, ADORowClass), \ Modify}, #define END_ADO_BINDING宏的定义也在icrsint.h文g里: #define END_ADO_BINDING() {0, adEmpty, 0, 0, 0, 0, 0, 0, 0, FALSE}};\ return rgADOBindingEntries;} |
_RecordsetPtr Rs1; IADORecordBinding *picRs=NULL; CCustomRs rs; ...... Rs1->QueryInterface(__uuidof(IADORecordBinding), (LPVOID*)&picRs)); picRs->BindToRecordset(&rs); |
//Set sort and filter condition: // Step 4: Manipulate the data Rs1->Fields->GetItem("au_lname")->Properties->GetItem("Optimize")->Value = true; Rs1->Sort = "au_lname ASC"; Rs1->Filter = "phone LIKE '415 5*'"; Rs1->MoveFirst(); while (VARIANT_FALSE == Rs1->EndOfFile) { printf("Name: %s\t %s\tPhone: %s\n", (rs.lau_fnameStatus == adFldOK ? rs.m_szau_fname : ""), (rs.lau_lnameStatus == adFldOK ? rs.m_szau_lname : ""), (rs.lphoneStatus == adFldOK ? rs.m_szphone : "")); if (rs.lphoneStatus == adFldOK) strcpy(rs.m_szphone, "777"); TESTHR(picRs->Update(&rs)); // Add change to the batch Rs1->MoveNext(); } Rs1->Filter = (long) adFilterNone; ...... if (picRs) picRs->Release(); Rs1->Close(); pConn->Close(); |
if(FAILED(picRs->AddNew(&rs))) ...... |
//写入一张照片到数据库: VARIANT varChunk; SAFEARRAY *psa; SAFEARRAYBOUND rgsabound[1]; //VT_ARRAY ?VT_UI1 CFile f("h:\\aaa.jpg",Cfile::modeRead); BYTE bVal[ChunkSize+1]; UINT uIsRead=0; //Create a safe array to store the array of BYTES while(1) { uIsRead=f.Read(bVal,ChunkSize); if(uIsRead==0)break; rgsabound[0].cElements =uIsRead; rgsabound[0].lLbound = 0; psa = SafeArrayCreate(VT_UI1,1,rgsabound); for(long index=0;index<uIsRead;index++) { if(FAILED(SafeArrayPutElement(psa,&index,&bVal[index]))) ::MessageBox(NULL,"啊,又出毛病了?,"提示",MB_OK ?MB_ICONWARNING); } varChunk.vt = VT_ARRAY│VT_UI1; varChunk.parray = psa; try{ m_pRecordset->Fields->GetItem("photo")->AppendChunk(varChunk); } catch (_com_error &e) { CString str=(char*)e.Description(); ::MessageBox(NULL,str+"\n又出毛病了?,"提示",MB_OK ?MB_ICONWARNING); } ::VariantClear(&varChunk); ::SafeArrayDestroyData( psa); if(uIsRead<ChunkSize)break; }//while(1) f.Close(); //从数据库M张照片: CFile f; f.Open("h:\\bbb.jpg",Cfile::modeWrite│Cfile::modeCreate); long lPhotoSize = m_pRecordset->Fields->Item["photo"]->ActualSize; long lIsRead=0; _variant_t varChunk; BYTE buf[ChunkSize]; while(lPhotoSize>0) { lIsRead=lPhotoSize>=ChunkSize? ChunkSize:lPhotoSize; varChunk = m_pRecordset->Fields-> Item["photo"]->GetChunk(lIsRead); for(long index=0;index<lIsRead;index++) { ::SafeArrayGetElement(varChunk.parray,&index,buf+index); } f.Write(buf,lIsRead); lPhotoSize-=lIsRead; }//while() f.Close(); |
VARIANT varChunk; SAFEARRAY *psa; SAFEARRAYBOUND rgsabound[1]; |
uIsRead=f.Read(bVal,ChunkSize);//read array from a file. if(uIsRead==0)break; rgsabound[0].cElements =uIsRead; rgsabound[0].lLbound = 0; psa = SafeArrayCreate(VT_UI1,1,rgsabound); |
for(long index=0;index<uIsRead;index++) { if(FAILED(SafeArrayPutElement(psa,&index,&bVal[index]))) ::MessageBox(NULL,"出毛病了?,"提示",MB_OK ?MB_ICONWARNING); } |
varChunk.vt = VT_ARRAY│VT_UI1; varChunk.parray = psa; |
BYTE buf[lIsRead]; for(long index=0;index<lIsRead;index++) { ::SafeArrayGetElement(varChunk.parray,&index,buf+index); } |
BYTE *buf; SafeArrayAccessData(varChunk.parray, (void **)&buf); f.Write(buf,lIsRead); SafeArrayUnaccessData(varChunk.parray); |
BYTE *buf; ::SafeArrayAccessData(psa, (void **)&buf); for(long index=0;index<uIsRead;index++) { buf[index]=bVal[index]; } ::SafeArrayUnaccessData(psa); varChunk.vt = VT_ARRAY│VT_UI1; varChunk.parray = psa; |
// Check for whether bookmark set for a record if (VarBookmark.vt == VT_EMPTY) printf("No Bookmark set!\n"); else rst->Bookmark = VarBookmark; |
rst->Filter = _bstr_t ("姓名='赵薇' AND 性别=’女?); |
rst->Filter = _bstr_t ("(姓名='赵薇' AND 性别=’女? OR AGE<25"); |
rst->Filter = _bstr_t ("(姓名='赵薇' OR 性别=’女? AND AGE<25"); |
rst->Filter = _bstr_t ("(姓名='赵薇' AND AGE<25) OR (性别=’女?AND AGE<25)"); |
rst->Filter = _bstr_t ("姓名 LIKE '*?' "); |
rst->Filter = _bstr_t ("姓名 LIKE '?' "); |
pRst->Fields->GetItem("姓名")->Properties-> GetItem("Optimize")->PutValue("True"); pRst->Find("姓名 = '赵薇'",1,adSearchForward); ...... pRst->Fields->GetItem("姓名")->Properties-> GetItem("Optimize")->PutValue("False"); pRst->Close(); |
pRstAuthors->CursorLocation = adUseClient; pRstAuthors->Open("SELECT * FROM mytable", _variant_t((IDispatch *) pConnection), adOpenStatic, adLockReadOnly, adCmdText); ...... pRst->Sort = "姓名 DESC, q龄 ASC"; |
pCnn->BeginTrans(); |
pCnn->CommitTrans (); |
pCnn->RollbackTrans (); |
"Provider=SQLOLEDB;Server=888;Trusted_Connection=yes" ";Database=master;uid=lad;"; |
"Provider=SQLOLEDB;Server=888;Database=master;uid=lad;pwd=111;"; |
try{ m_pConnect->Execute ( _bstr_t("USE INSURANCE_2002"),NULL, adCmdText│adExecuteNoRecords ); } catch (_com_error &e) { blSuccess=FALSE; CString str="数据库INSURANCE_2002不存在!\n"; str+=e.Description(); ::MessageBox(NULL,str,"警告",MB_OK ?MB_ICONWARNING); } |
try{ m_pRecordset->Open(_variant_t("mytable"), _variant_t((IDispatch *)m_pConnection,true), adOpenKeyset, adLockOptimistic, adCmdTable); } catch (_com_error &e) { ::MessageBox(NULL,"该表不存在?,"提示",MB_OK ?MB_ICONWARNING); } |
SAFEARRAY *psa; ...... //When the data are no longer to be used: ::SafeArrayDestroyData( psa); |
#import "C:\Program Files\Common Files\System\ADO\msado15.dll" \ no_namespace rename("EOF", "EndOfFile") |
CLSID clsid; HRESULT hr = ::CLSIDFromProgID(L"ADODB.Connection", &clsid); if(FAILED(hr)) {...} ::CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IDispatch, (void **) &pDispatch); if(FAILED(hr)) {...} |
#include <icrsint.h> //Include support for VC++ Extensions #import "C:\Program Files\Common Files\System\ADO\msado15.dll" \ no_namespace rename("EOF", "adoEOF") |
_COM_SMARTPTR_TYPEDEF(_Collection, __uuidof(_Collection)); |
_ConnectionPtr pMyConnect=NULL; HRESULT hr=pMyConnect.CreateInstance(__uuidof(Connection))); if(FAILED(hr))return; _bstr_t strConnect="Provider=SQLOLEDB; Server=server_name;" "Database=database_name; uid=user_name; pwd=password;"; //connecting to the database server now: try{pMyConnect->Open(strConnect,"","",NULL);} catch (_com_error &e) { ::MessageBox(NULL,e.Description(),"警告",MB_OK ?MB_ICONWARNING); } |
_bstr_t strConnect="DSN=datasource_name; Database=database_name; uid=user_name; pwd=password;"; |
_RecordsetPtr m_pRecordset; if(!FAILED(m_pRecordset.CreateInstance( __uuidof( Recordset ))) { m_pDoc->m_initialized=FALSE; return; } try{ m_pRecordset->Open(_variant_t("mytable"), _variant_t((IDispatch *)pMyConnect,true), adOpenKeyset, adLockOptimistic, adCmdTable); } catch (_com_error &e) { ::MessageBox(NULL,"无法打开mytable表?,"提示", MB_OK ?MB_ICONWARNING); } |
try{ m_pRecordset->MoveFirst(); while(m_pRecordset->adoEOF==VARIANT_FALSE) { //Retrieve column's value: CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem (_variant_t("name"))->Value); short cAge=(short)(m_pRecordset->Fields->GetItem (_variant_t("age"))->Value); //Do something what you want to do: ...... m_pRecordset->MoveNext(); } }//try catch (_com_error &e) { CString str=(char*)e.Description(); ::MessageBox(NULL,str+"\n又出毛病了?,"提示", MB_OK ?MB_ICONWARNING); } |
CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem (_variant_t("name"))->GetValue()); |
try{ m_pRecordset->MoveFirst(); while(m_pRecordset->adoEOF==VARIANT_FALSE) { m_pRecordset->Fields->GetItem (_variant_t("姓名"))->Value=_bstr_t("赵薇"); ...... m_pRecordset->Update(); m_pRecordset->MoveNext(); } }//try |
m_pRecordset->Fields->GetItem (_variant_t("姓名"))->PutValue(_bstr_t("赵薇")); |
// Add new record into this table: try{ if(!m_pRecordset->Supports(adAddNew)) return; m_pRecordset->AddNew(); m_pRecordset->Fields->GetItem (_variant_t("姓名"))->Value=_bstr_t("赵薇"); m_pRecordset->Fields->GetItem (_variant_t("性别"))->Value=_bstr_t("?); m_pRecordset->Fields->GetItem (_variant_t("age"))->Value=_variant_t((short)20); m_pRecordset->Fields->GetItem (_variant_t("marry"))->Value=_bstr_t("未婚"); m_pRecordset->Update(); }//try catch (_com_error &e) { ::MessageBox(NULL, "又出毛病了?,"提示",MB_OK ?MB_ICONWARNING); } |
_variant_t varName[4],narValue[4]; varName[0] = L"姓名"; varName[1] = L"性别"; varName[2] = L"age"; varName[3] = L"marry"; narValue[0]=_bstr_t("赵薇"); narValue[1]=_bstr_t("?); narValue[2]=_variant_t((short)20); narValue[3]=_bstr_t("未婚"); const int nCrit = sizeof varName / sizeof varName[0]; // Create SafeArray Bounds and initialize the array SAFEARRAYBOUND rgsaName[1],rgsaValue[1]; rgsaName[0].lLbound = 0; rgsaName[0].cElements = nCrit; SAFEARRAY *psaName = SafeArrayCreate( VT_VARIANT, 1, rgsaName ); rgsaValue[0].lLbound = 0; rgsaValue[0].cElements = nCrit; SAFEARRAY *psaValue = SafeArrayCreate( VT_VARIANT, 1, rgsaValue ); // Set the values for each element of the array HRESULT hr1=S_OK.hr2=S_OK; for( long i = 0 ; i < nCrit && SUCCEEDED( hr1 ) && SUCCEEDED( hr2 );i++) { hr1=SafeArrayPutElement(psaName, &i,&varName[i]); hr2=SafeArrayPutElement(psaValue, &i,&narValue[i]); } // Initialize and fill the SafeArray VARIANT vsaName,vsaValue; vsaName.vt = VT_VARIANT ?VT_ARRAY; vsaValue.vt = VT_VARIANT ?VT_ARRAY; V_ARRAY(&vsaName) = psaName;//&vsaName->parray=psaName; //see definition in oleauto.h file. V_ARRAY(&vsaValue) = psaValue; // Add a new record: m_pRecordset->AddNew(vsaName,vsaValue); |
try{ m_pRecordset->MoveFirst(); while(m_pRecordset->adoEOF==VARIANT_FALSE) { CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem (_variant_t("姓名"))->Value); if(::MessageBox(NULL,"姓名="+sName+"\n删除她吗Q?, "提示",MB_YESNO ?MB_ICONWARNING)==IDYES) { m_pRecordset->Delete(adAffectCurrent); m_pRecordset->Update(); } m_pRecordset->MoveNext(); } }//try catch (_com_error &e) { ::MessageBox(NULL,"又出毛病了?,"提示",MB_OK ?MB_ICONWARNING); } |
_ConnectionPtr Conn1; _CommandPtr Cmd1; ParametersPtr *Params1 = NULL; // Not an instance of a smart pointer. _ParameterPtr Param1; _RecordsetPtr Rs1; try { // Create Connection Object (1.5 Version) Conn1.CreateInstance( __uuidof( Connection ) ); Conn1->ConnectionString = bstrConnect; Conn1->Open( bstrEmpty, bstrEmpty, bstrEmpty, -1 ); // Create Command Object Cmd1.CreateInstance( __uuidof( Command ) ); Cmd1->ActiveConnection = Conn1; Cmd1->CommandText = _bstr_t("SELECT * FROM mytable WHERE age< ?"); }//try |
Cmd1->ActiveConnection = Conn1; |
// Create Parameter Object Param1 = Cmd1->CreateParameter( _bstr_t(bstrEmpty), adInteger, adParamInput, -1, _variant_t( (long) 5) ); Param1->Value = _variant_t( (long) 5 ); Cmd1->Parameters->Append( Param1 ); |
// Open Recordset Object Rs1 = Cmd1->Execute( &vtEmpty, &vtEmpty2, adCmdText ); |
try{ m_pRecordset->Open((IDispatch *) Cmd1, vtMissing, adOpenStatic, adLockOptimistic, adCmdUnspecified); } catch (_com_error &e) { ::MessageBox(NULL,"mytable表不存在?,"提示",MB_OK ?MB_ICONWARNING); } |
class CConnEvent : public ConnectionEventsVt { private: ULONG m_cRef; public: CConnEvent() { m_cRef = 0; }; ~CConnEvent() {}; STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP raw_InfoMessage( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); STDMETHODIMP raw_BeginTransComplete( LONG TransactionLevel, struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection); ...... }; |
STDMETHODIMP CConnEvent::raw_InfoMessage( struct Error *pError, EventStatusEnum *adStatus, struct _Connection *pConnection) { *adStatus = adStatusUnwantedEvent; return S_OK; }; |
STDMETHODIMP CConnEvent::QueryInterface(REFIID riid, void ** ppv) { *ppv = NULL; if (riid == __uuidof(IUnknown) ││ riid == __uuidof(ConnectionEventsVt)) *ppv = this; if (*ppv == NULL) return ResultFromScode(E_NOINTERFACE); AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CConnEvent::AddRef() { return ++m_cRef; }; STDMETHODIMP_(ULONG) CConnEvent::Release() { if (0 != --m_cRef) return m_cRef; delete this; return 0; } |
// Start using the Connection events IConnectionPointContainer *pCPC = NULL; IConnectionPoint *pCP = NULL; hr = pConn.CreateInstance(__uuidof(Connection)); if (FAILED(hr)) return; hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer), (void **)&pCPC); if (FAILED(hr)) return; hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return; pConnEvent = new CConnEvent(); hr = pConnEvent->QueryInterface(__uuidof(IUnknown), (void **) &pUnk); if (FAILED(hr)) return rc; hr = pCP->Advise(pUnk, &dwConnEvt); pCP->Release(); if (FAILED(hr)) return; pConn->Open("dsn=Pubs;", "sa", "", adConnectUnspecified); |
pConn->Close(); // Stop using the Connection events hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer), (void **) &pCPC); if (FAILED(hr)) return; hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP); pCPC->Release(); if (FAILED(hr)) return rc; hr = pCP->Unadvise( dwConnEvt ); pCP->Release(); if (FAILED(hr)) return; |
CString CZjyDlg::VariantToString(VARIANT var)
{
CString strValue;
_variant_t var_t;
_bstr_t bstr_t;
time_t cur_time;
CTime time_value;
COleCurrency var_currency;
switch(var.vt)
{
case VT_EMPTY:
case VT_NULL:strValue=_T("");break;
case VT_UI1:strValue.Format("%d",var.bVal);break;
case VT_I2:strValue.Format("%d",var.iVal);break;
case VT_I4:strValue.Format("%d",var.lVal);break;
case VT_R4:strValue.Format("%f",var.fltVal);break;
case VT_R8:strValue.Format("%f",var.dblVal);break;
case VT_CY:
var_currency=var;
strValue=var_currency.Format(0);break;
case VT_BSTR:
var_t =var;
bstr_t=var_t;
strValue.Format("%s",(const char *)bstr_t);break;
case VT_DATE:
cur_time=var.date;
time_value=cur_time;
strValue.Format("%A,%B,%d,%Y");break;
case VT_BOOL:strValue.Format("%d",var.boolVal);break;
default:strValue=_T("");break;
}
return strValue;
}
本例中的name和age都是字段名,d的字D值分别保存在sName和cAge变量内。例中的Fields是Recordset对象的容器,GetItemҎq回的是Field对象Q而Value则是Field对象的一个属性(卌字段的|。通过此例Q应掌握操纵对象属性的Ҏ。例如,要获得Field 对象的Value属性的值可以直接用属性名Value来引用它Q如上例Q,但也可以调用GetҎQ例如:
CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem
(_variant_t("name"))->GetValue());
从此例还可以看到Q判断是否到达记录集的末,使用记录集的adoEOF属性,其D为真卛_了结,反之则未到。判断是否到达记录集开_则可用BOF属性?BR>另外Q读取数据还有一个方法,是定义一个绑定的c,然后通过l定的变量得到字D|详见后面的介l)?BR>5、修Ҏ?BR>Ҏ一Q?BR> try{
m_pRecordset->MoveFirst();
while(m_pRecordset->adoEOF==VARIANT_FALSE)
{
m_pRecordset->Fields->GetItem
(_variant_t("姓名"))->Value=_bstr_t("赵薇");
......
m_pRecordset->Update();www.chinai tp 采吧采吧不是|?ow er.comJuJIe
m_pRecordset->MoveNext();
}
}//try
改变了Value属性的|x变了字段的倹{?BR>Ҏ二:
m_pRecordset->Fields->GetItem
(_variant_t("姓名"))->PutValue(_bstr_t("赵薇"));
Ҏ三:是用定义绑定类的方法(详见后面的介l)?BR>6、添加记?BR>新记录添加成功后Q即自动成ؓ当前记录。AddNewҎ有两UŞ式,一个含有参敎ͼ而另一个则不带参数?BR>Ҏ一Q不带参敎ͼQ?BR> // Add new record into this table:
try{
if(!m_pRecordset->Supports(adAddNew)) return;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
m_pRecordset->AddNew();
m_pRecordset->Fields->GetItem
(_variant_t("姓名"))->Value=_bstr_t("赵薇");
m_pRecordset->Fields->GetItem
(_variant_t("性别"))->Value=_bstr_t("?);
m_pRecordset->Fields->GetItem
(_variant_t("age"))->Value=_variant_t((short)20);
m_pRecordset->Fields->GetItem
(_variant_t("marry"))->Value=_bstr_t("未婚");
m_pRecordset->Update();
}//try
catch (_com_error &e)
{
::MessageBox(NULL, "又出毛病了?,"提示",MB_OK | MB_ICONWARNING);
}
q种Ҏ弄完了还要调用Update()?BR>Ҏ二(带参敎ͼQ?BR> _variant_t varName[4],narValue[4];
varName[0] = L"姓名";
varName[1] = L"性别";
varName[2] = L"age";
varName[3] = L"marry";
narValue[0]=_bstr_t("赵薇");
narValue[1]=_bstr_t("?);
narValue[2]=_variant_t((short)20);
narValue[3]=_bstr_t("未婚");www.chinai tp 采吧采吧不是|?ow er.comJuJIe
const int nCrit = sizeof varName / sizeof varName[0];
// Create SafeArray Bounds and initialize the array
SAFEARRAYBOUND rgsaName[1],rgsaValue[1];
rgsaName[0].lLbound = 0;
rgsaName[0].cElements = nCrit;
SAFEARRAY *psaName = SafeArrayCreate( VT_VARIANT, 1, rgsaName );
rgsaValue[0].lLbound = 0;
rgsaValue[0].cElements = nCrit;
SAFEARRAY *psaValue = SafeArrayCreate( VT_VARIANT, 1, rgsaValue );
// Set the values for each element of the array
HRESULT hr1=S_OK.hr2=S_OK;
for( long i = 0 ; i < nCrit && SUCCEEDED( hr1 ) && SUCCEEDED( hr2 );i++)
{
hr1=SafeArrayPutElement(psaName, &i,&varName[i]);
hr2=SafeArrayPutElement(psaValue, &i,&narValue[i]); }
// Initialize and fill the SafeArray
VARIANT vsaName,vsaValue;
vsaName.vt = VT_VARIANT | VT_ARRAY;
vsaValue.vt = VT_VARIANT | VT_ARRAY;
V_ARRAY(&vsaName) = psaName;//&vsaName->parray=psaName;
//see definition in oleauto.h file.
V_ARRAY(&vsaValue) = psaValue;
// Add a new record:
m_pRecordset->AddNew(vsaName,vsaValue);
q种Ҏ不需要调用UpdateQ因为添加后QADO会自动调用它。此Ҏ主要是用SafeArray挺麻烦?BR>Ҏ三:是用定义绑定类的方法(详见后面的介l)?BR>7、删除记?BR>调用Recordset的DeleteҎp了,删除的是当前记录。要了解Delete的其它用法请查阅参考文献?BR> try{
m_pRecordset->MoveFirst();
while(m_pRecordset->adoEOF==VARIANT_FALSE)
{
CString sName=(char*)(_bstr_t)(m_pRecordset->Fields->GetItem
(_variant_t("姓名"))->Value);
if(::MessageBox(NULL,"姓名="+sName+"\n删除她吗Q?,
"提示",MB_YESNO | MB_ICONWARNING)==IDYES)
{
m_pRecordset->Delete(adAffectCurrent);
m_pRecordset->Update();
}
m_pRecordset->MoveNext();
}
}//try
catch (_com_error &e)
{
::MessageBox(NULL,"又出毛病了?,"提示",MB_OK | MB_ICONWARNING);
}
8、用带参数的命?BR>Command对象所代表的就是一个Provider能够理解的命令,如SQL语句{。用Command对象的关键就是把表示命o的语句设|到CommandText属性中Q然后调用Command对象的ExecuteҎp了。一般情况下在命令中无需使用参数Q但有时使用参数Q可以增加其灉|性和效率?BR>(1). 建立q接、命令对象和记录集对?BR>本例中表C命令的语句是一个SQL语句QSELECT语句Q。SELECT语句中的问号?׃表参敎ͼ如果要多个参敎ͼ多攑և个问P每个问号代表一个参数?BR>_ConnectionPtr Conn1;
_CommandPtr Cmd1;
ParametersPtr *Params1 = NULL; // Not an instance of a smart pointer.
_ParameterPtr Param1;
_RecordsetPtr Rs1;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
try
{
// Create Connection Object (1.5 Version)
Conn1.CreateInstance( __uuidof( Connection ) );
Conn1->ConnectionString = bstrConnect;
Conn1->Open( bstrEmpty, bstrEmpty, bstrEmpty, -1 );
// Create Command Object
Cmd1.CreateInstance( __uuidof( Command ) );
Cmd1->ActiveConnection = Conn1;
Cmd1->CommandText = _bstr_t("SELECT * FROM mytable WHERE age< ?");
}//try
要注意命令对象必Mq接对象兌h才能起作用,本例中将命o对象的ActiveConnection属性设|ؓq接对象的指针,即ؓ此目的:
Cmd1->ActiveConnection = Conn1;
(2). 创徏参数对象Qƈl参数赋?BR>// Create Parameter Object
Param1 = Cmd1->CreateParameter( _bstr_t(bstrEmpty),
adInteger,
adParamInput,
-1,
_variant_t( (long) 5) );
Param1->Value = _variant_t( (long) 5 );
Cmd1->Parameters->Append( Param1 );
用命令对象的Ҏ来创Z个参数对象,其中的长度参敎ͼW三个)如果是固定长度的cdQ就?1Q如果是字符串等可变长度的就填其实际长度。Parameters是命令对象的一个容器,它的AppendҎ是把创建的参数对象q加到该容器里。Appendq去的参数按先后序与SQL语句中的问号从左臛_一一对应?BR>(3). 执行命o打开记录?BR>// Open Recordset Object
Rs1 = Cmd1->Execute( &vtEmpty, &vtEmpty2, adCmdText );
但要注意Q用Command和Connection对象的ExecuteҎ得到的Recordset是只ȝ。因为在打开Recordset之前Q我们无法设|它的LockType属性(光认gؓ只读Q。而在打开之后讄LockType不v作用?BR>我发现用上述Ҏ得到记录集Rs1后,不但Rs1中的记录无法修改Q即使直接用SQL语句修改同一表中M记录都不行?BR>要想能修Ҏ据,q是要用Recordset自己的OpenҎ才行Q如Q?BR> try{
m_pRecordset->Open((IDispatch *) Cmd1, vtMissing,
adOpenStatic, adLockOptimistic, adCmdUnspecified);
}
catch (_com_error &e)
{
::MessageBox(NULL,"mytable表不存在?,"提示",MB_OK | MB_ICONWARNING);
}
Recordset对象的OpenҎ真是太好了,其第一个参数可以是SQL语句、表名字、命令对象指针等{?BR>9、响应ADO的通知事g
通知事g是当某个特定事件发生时Q由Provider通知客户E序Q换句话_是由Provider调用客户E序中的一个特定的ҎQ即事g的处理函敎ͼ。所以ؓ了响应一个事Ӟ最关键的就是要实现事g的处理函数?BR>(1). 从ConnectionEventsVt接口zZ个类
Z响应_Connection的通知事gQ应该从ConnectionEventsVt接口zZ个类Q?BR>class CConnEvent : public ConnectionEventsVt
{
private:
ULONG m_cRef;
public:
CConnEvent() { m_cRef = 0; };
~CConnEvent() {};www.chinai tp 采吧采吧不是|?ow er.comJuJIe
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP raw_InfoMessage(
struct Error *pError,
EventStatusEnum *adStatus,
struct _Connection *pConnection);
STDMETHODIMP raw_BeginTransComplete(
LONG TransactionLevel,
struct Error *pError,
EventStatusEnum *adStatus,
struct _Connection *pConnection);
......
};
(2). 实现每一个事件的处理函数(凡是带raw_前缀的方法都把它实现?Q?BR>STDMETHODIMP CConnEvent::raw_InfoMessage(
struct Error *pError,
EventStatusEnum *adStatus,
struct _Connection *pConnection)
{
*adStatus = adStatusUnwantedEvent;
return S_OK;
};www.chinai tp 采吧采吧不是|?ow er.comJuJIe
有些Ҏ虽然你ƈ不需要,但也必须实现它,只需单地q回一个S_OK卛_。但如果要避免经常被调用Q还应在其中adStatus参数讄为adStatusUnwantedEventQ则在本ơ调用后Q以后就不会被调用了?BR>另外q必d现QueryInterface, AddRef, 和Release三个Ҏ:
STDMETHODIMP CConnEvent::QueryInterface(REFIID riid, void ** ppv)
{
*ppv = NULL;
if (riid == __uuidof(IUnknown) ||
riid == __uuidof(ConnectionEventsVt)) *ppv = this;
if (*ppv == NULL)
return ResultFromScode(E_NOINTERFACE);
AddRef();
return NOERROR;
}
STDMETHODIMP_(ULONG) CConnEvent::AddRef() { return ++m_cRef; };
STDMETHODIMP_(ULONG) CConnEvent::Release()
{
if (0 != --m_cRef) return m_cRef;
delete this;
return 0;
}
(3). 开始响应通知事g
// Start using the Connection events
IConnectionPointContainer *pCPC = NULL;
IConnectionPoint *pCP = NULL;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
hr = pConn.CreateInstance(__uuidof(Connection));
if (FAILED(hr)) return;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer),
(void **)&pCPC);
if (FAILED(hr)) return;
hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP);
pCPC->Release();
if (FAILED(hr)) return;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
pConnEvent = new CConnEvent();
hr = pConnEvent->QueryInterface(__uuidof(IUnknown), (void **) &pUnk);
if (FAILED(hr)) return rc;
hr = pCP->Advise(pUnk, &dwConnEvt);
pCP->Release();
if (FAILED(hr)) return;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
pConn->Open("dsn=Pubs;", "sa", "", adConnectUnspecified);
也就是说在连?Open)之前做q些事?BR>(4). 停止响应通知事g
pConn->Close();
// Stop using the Connection events
hr = pConn->QueryInterface(__uuidof(IConnectionPointContainer),
(void **) &pCPC);
if (FAILED(hr)) return;
hr = pCPC->FindConnectionPoint(__uuidof(ConnectionEvents), &pCP);
pCPC->Release();
if (FAILED(hr)) return rc;
hr = pCP->Unadvise( dwConnEvt );
pCP->Release();
if (FAILED(hr)) return;
在连接关闭之后做qg事?
10、邦定数?BR>定义一个绑定类Q将其成员变量绑定到一个指定的记录集,以方便于讉K记录集的字段倹{?BR>(1). 从CADORecordBindingzZ个类Q?BR>class CCustomRs : public CADORecordBinding
{
BEGIN_ADO_BINDING(CCustomRs)
ADO_VARIABLE_LENGTH_ENTRY2(3, adVarChar, m_szau_fname,
sizeof(m_szau_fname), lau_fnameStatus, false)
ADO_VARIABLE_LENGTH_ENTRY2(2, adVarChar, m_szau_lname,
sizeof(m_szau_lname), lau_lnameStatus, false)
ADO_VARIABLE_LENGTH_ENTRY2(4, adVarChar, m_szphone,
sizeof(m_szphone), lphoneStatus, true)
END_ADO_BINDING()www.chinai tp 采吧采吧不是|?ow er.comJuJIe
public:
CHAR m_szau_fname[22];
ULONG lau_fnameStatus;
CHAR m_szau_lname[42];
ULONG lau_lnameStatus;
CHAR m_szphone[14];
ULONG lphoneStatus;
};
其中要l定的字D与变量名用BEGIN_ADO_BINDING宏关联v来。每个字D对应于两个变量Q一个存攑֭D늚|另一个存攑֭D늚状态。字D는?开始的序号表示Q如1Q?Q?{等?BR>特别要注意的是:如果要绑定的字段是字W串cdQ则对应的字W数l的元素个数一定要比字D长度大2Q比如m_szau_fname[22]Q其l定的字Dau_fname的长度实际是20Q,不这L定就会失败。我分析多出?可能是ؓ了存攑֭W串l尾的空字符null和BSTR字符串开头的一个字Q表CBSTR的长度)。这个问题对于初学者来说可能是一个意想不到的问题?BR>CADORecordBindingcȝ定义在icrsint.h文g里,内容是:
class CADORecordBinding
{
public:
STDMETHOD_(const ADO_BINDING_ENTRY*, GetADOBindingEntries) (VOID) PURE;
};www.chinai tp 采吧采吧不是|?ow er.comJuJIe
BEGIN_ADO_BINDING宏的定义也在icrsint.h文g里,内容是:
#define BEGIN_ADO_BINDING(cls) public: \
typedef cls ADORowClass; \
const ADO_BINDING_ENTRY* STDMETHODCALLTYPE GetADOBindingEntries() { \
static const ADO_BINDING_ENTRY rgADOBindingEntries[] = { www.chinai tp 采吧采吧不是|?ow er.comJuJIe
ADO_VARIABLE_LENGTH_ENTRY2宏的定义也在icrsint.h文g里:
#define ADO_VARIABLE_LENGTH_ENTRY2(Ordinal, DataType, Buffer, Size, Status, Modify)\
{Ordinal, \
DataType, \
0, \
0, \
Size, \
offsetof(ADORowClass, Buffer), \
offsetof(ADORowClass, Status), \
0, \
classoffset(CADORecordBinding, ADORowClass), \
Modify},www.chinai tp 采吧采吧不是|?ow er.comJuJIe
#define END_ADO_BINDING宏的定义也在icrsint.h文g里:
#define END_ADO_BINDING() {0, adEmpty, 0, 0, 0, 0, 0, 0, 0, FALSE}};\
return rgADOBindingEntries;}
(2). l定
_RecordsetPtr Rs1;
IADORecordBinding *picRs=NULL;
CCustomRs rs;
......
Rs1->QueryInterface(__uuidof(IADORecordBinding),
(LPVOID*)&picRs));
picRs->BindToRecordset(&rs);
z出的cd通过IADORecordBinding接口才能l定Q调用它的BindToRecordsetҎp了?BR>(3). rs中的变量x当前记录字段的?BR>//Set sort and filter condition:
// Step 4: Manipulate the data
Rs1->Fields->GetItem("au_lname")->Properties->GetItem("Optimize")->Value = true;
Rs1->Sort = "au_lname ASC";
Rs1->Filter = "phone LIKE '415 5*'";www.chinai tp 采吧采吧不是|?ow er.comJuJIe
Rs1->MoveFirst();
while (VARIANT_FALSE == Rs1->EndOfFile)
{
printf("Name: %s\t %s\tPhone: %s\n",
(rs.lau_fnameStatus == adFldOK ? rs.m_szau_fname : ""),
(rs.lau_lnameStatus == adFldOK ? rs.m_szau_lname : ""),
(rs.lphoneStatus == adFldOK ? rs.m_szphone : ""));
if (rs.lphoneStatus == adFldOK)
strcpy(rs.m_szphone, "777");
TESTHR(picRs->Update(&rs)); // Add change to the batch
Rs1->MoveNext();
}
Rs1->Filter = (long) adFilterNone;
......
if (picRs) picRs->Release();
Rs1->Close();
pConn->Close();
只要字段的状态是adFldOKQ就可以讉K。如果修改了字段Q不要忘了先调用picRs的UpdateQ注意不是Recordset的UpdateQ,然后才关闭,也不要忘了释放picRsQ即picRs->Release();Q?BR>(4). 此时q可以用IADORecordBinding接口d新纪?BR> if(FAILED(picRs->AddNew(&rs)))
......
11. 讉K长数?BR>在Microsoft SQL中的长数据包括text、image{这样长cd的数据,作ؓ二进制字节来对待?BR>可以用Field对象的GetChunk和AppendChunkҎ来访问。每ơ可以读出或写入全部数据的一部分Q它会记住上ơ访问的位置。但是如果中间访问了别的字段后,又得从头来了?BR>L下面的例子:
//写入一张照片到数据库:
VARIANT varChunk;
SAFEARRAY *psa;
SAFEARRAYBOUND rgsabound[1];www.chinai tp 采吧采吧不是|?ow er.comJuJIe
//VT_ARRAY | VT_UI1
CFile f("h:\\aaa.jpg",CFile::modeRead);
BYTE bVal[ChunkSize+1];
UINT uIsRead=0;
//Create a safe array to store the array of BYTES
while(1)
{
uIsRead=f.Read(bVal,ChunkSize);
if(uIsRead==0)break;
rgsabound[0].cElements =uIsRead;
rgsabound[0].lLbound = 0;
psa = SafeArrayCreate(VT_UI1,1,rgsabound);
for(long index=0;index<uIsRead;index++)
{
if(FAILED(SafeArrayPutElement(psa,&index,&bVal[index])))
::MessageBox(NULL,"啊,又出毛病了?,"提示",MB_OK | MB_ICONWARNING);
}
varChunk.vt = VT_ARRAY|VT_UI1;
varChunk.parray = psa;
try{
m_pRecordset->Fields->GetItem("photo")->AppendChunk(varChunk);
}
catch (_com_error &e)
{
CString str=(char*)e.Description();
::MessageBox(NULL,str+"\n又出毛病了?,"提示",MB_OK | MB_ICONWARNING);
}
::VariantClear(&varChunk);
::SafeArrayDestroyData( psa);
if(uIsRead<ChunkSize)break;
}//while(1)
f.Close();www.chinai tp 采吧采吧不是|?ow er.comJuJIe
//从数据库M张照片:
CFile f;
f.Open("h:\\bbb.jpg",CFile::modeWrite|CFile::modeCreate);
long lPhotoSize = m_pRecordset->Fields->Item["photo"]->ActualSize;
long lIsRead=0;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
_variant_t varChunk;
BYTE buf[ChunkSize];
while(lPhotoSize>0)
{
lIsRead=lPhotoSize>=ChunkSize? ChunkSize:lPhotoSize;
varChunk = m_pRecordset->Fields->
Item["photo"]->GetChunk(lIsRead);
for(long index=0;index<lIsRead;index++)
{
::SafeArrayGetElement(varChunk.parray,&index,buf+index);
}
f.Write(buf,lIsRead);
lPhotoSize-=lIsRead;
}//while()
f.Close();
12. 使用SafeArray问题
学会使用SafeArray也是很重要的Q因为在ADO~程中经常要用。它的主要目的是用于automation中的数组型参数的传递。因为在|络环境中,数组是不能直接传递的Q而必d其包装成SafeArray。实质上SafeArray是通常的数l增加一个描q符Q说明其l数、长度、边界、元素类型等信息。SafeArray也ƈ不单独用,而是其再包装到VARIANTcd的变量中Q然后才作ؓ参数传送出厅R在VARIANT的vt成员的值如果包含VT_ARRAY|...,那么它所装的就是一个SafeArrayQ它的parray成员x指向SafeArray的指针。SafeArray中元素的cd可以是VARIANT能封装的McdQ包括VARIANTcd本n?nbsp;
使用SafeArray的具体步骤:
Ҏ一Q?BR> 包装一个SafeArrayQ?BR>(1). 定义变量Q如Q?BR> VARIANT varChunk;
SAFEARRAY *psa;
SAFEARRAYBOUND rgsabound[1];
(2). 创徏SafeArray描述W:
uIsRead=f.Read(bVal,ChunkSize);//read array from a file.
if(uIsRead==0)break;
rgsabound[0].cElements =uIsRead;
rgsabound[0].lLbound = 0;
psa = SafeArrayCreate(VT_UI1,1,rgsabound);
(3). 攄数据元素到SafeArrayQ?BR> for(long index=0;index<uIsRead;index++)
{
if(FAILED(SafeArrayPutElement(psa,&index,&bVal[index])))
::MessageBox(NULL,"出毛病了?,"提示",MB_OK | MB_ICONWARNING);
}
一个一个地放,挺麻烦的?BR>(4). 装到VARIANT内:
varChunk.vt = VT_ARRAY|VT_UI1;
varChunk.parray = psa;
q样可以将varChunk作ؓ参数传送出M?FONT color=#ffffcc>www.chinai tp 采吧采吧不是|?ow er.comJuJIe
dSafeArray中的数据的步骤:
(1). 用SafeArrayGetElement一个一个地?BR> BYTE buf[lIsRead];
for(long index=0;index<lIsRead;index++)
{
::SafeArrayGetElement(varChunk.parray,&index,buf+index);
}
p到缓冲区buf里了?BR>Ҏ二:
使用SafeArrayAccessData直接dSafeArray的缓冲区Q?BR>(1). ȝ冲区Q?BR> BYTE *buf;
SafeArrayAccessData(varChunk.parray, (void **)&buf);
f.Write(buf,lIsRead);
SafeArrayUnaccessData(varChunk.parray);
(2). 写缓冲区Q?BR> BYTE *buf;
::SafeArrayAccessData(psa, (void **)&buf);
for(long index=0;index<uIsRead;index++)
{
buf[index]=bVal[index];
}
::SafeArrayUnaccessData(psa);www.chinai tp 采吧采吧不是|?ow er.comJuJIe
varChunk.vt = VT_ARRAY|VT_UI1;
varChunk.parray = psa;www.chinai tp 采吧采吧不是|?ow er.comJuJIe
q种ҎdSafeArray都可以,它直接操USafeArray的数据缓冲区Q比用SafeArrayGetElement和SafeArrayPutElement速度快。特别适合于读取数据。但用完之后不要忘了调用::SafeArrayUnaccessData(psa)Q否则会出错的?BR>13. 使用书签( bookmark )
书签可以唯一标识记录集中的一个记录,用于快速地当前记录移回到已访问过的记录,以及q行qo{等。Provider会自动ؓ记录集中的每一条记录生一个书{,我们只需要用它p了。我们不能试图显C、修Ҏ比较书签。ADO用记录集的Bookmark属性表C当前记录的书签?BR>用法步骤Q?BR>(1). 建立一个VARIANTcd的变?BR>_variant_t VarBookmark;
(2). 当前记录的书签值存入该变量
也就是记录集的Bookmark属性的当前倹{?BR> VarBookmark = rst->Bookmark;
(3). q回到先前的记录
保存的书签D|到记录集的书签属性中Q?BR> // Check for whether bookmark set for a record
if (VarBookmark.vt == VT_EMPTY)
printf("No Bookmark set!\n");
else
rst->Bookmark = VarBookmark;
讄完后Q当前记录即会移动到该书{指向的记录?BR>14、设|过滤条?BR>Recordset对象的Filter属性表CZ当前的过滤条件。它的值可以是以AND或ORq接h的条件表辑ּQ不含WHERE关键字)、由书签l成的数l或ADO提供的FilterGroupEnum枚D倹{ؓFilter属性设|新值后Recordset的当前记录指针会自动Ud到满滤条件的W一个记录。例如:
rst->Filter = _bstr_t ("姓名='赵薇' AND 性别=’女?);
在用条件表辑ּ时应注意下列问题Q?BR>Q?Q、可以用圆括L成复杂的表达?BR>例如Q?BR>rst->Filter = _bstr_t ("(姓名='赵薇' AND 性别=’女? OR AGE<25");
但是微Y不允许在括号内用ORQ然后在括号外用ANDQ例如:
rst->Filter = _bstr_t ("(姓名='赵薇' OR 性别=’女? AND AGE<25");
必须修改为:
rst->Filter = _bstr_t ("(姓名='赵薇' AND AGE<25) OR (性别=’女?nbsp; AND AGE<25)");
Q?Q、表辑ּ中的比较q算W可以是LIKE
LIKE后被比较的是一个含有通配W?的字W串Q星可Cq个L的字W?BR>字符串的首部和尾部可以同时带星号*
rst->Filter = _bstr_t ("姓名 LIKE '*?' ");
也可以只是尾部带星号Q?BR>rst->Filter = _bstr_t ("姓名 LIKE '?' ");
Filter属性值的cd是VariantQ如果过滤条件是׃{成的数组Q则需该数组转换为SafeArrayQ然后再装C个VARIANT或_variant_t型的变量中,再赋lFilter属性?BR>15、烦引与排序
Q?Q、徏立烦?BR>当以某个字段为关键字用FindҎ查找ӞZ加快速度可以以该字段为关键字在记录集内部临时建立索引。只要将该字D늚Optimize属性设|ؓtrue卛_Q例如:
pRst->Fields->GetItem("姓名")->Properties->
GetItem("Optimize")->PutValue("True");
pRst->Find("姓名 = '赵薇'",1,adSearchForward);
......
pRst->Fields->GetItem("姓名")->Properties->
GetItem("Optimize")->PutValue("False");
pRst->Close();
说明QOptimize属性是由Provider提供的属性(在ADO中称为动态属性)QADO本n没有此属性?BR>Q?Q、排?BR>要排序也很简单,只要把要排序的关键字列表讄到Recordset对象的Sort属性里卛_Q例如:
pRstAuthors->CursorLocation = adUseClient;
pRstAuthors->Open("SELECT * FROM mytable",
_variant_t((IDispatch *) pConnection),
adOpenStatic, adLockReadOnly, adCmdText);
......
pRst->Sort = "姓名 DESC, q龄 ASC";
关键字(卛_D名Q之间用逗号隔开Q如果要以某关键字降序排序,则应在该关键字后加一I格Q再加DESCQ如上例Q。升序时ASC加不加无所谓。本操作是利用烦引进行的Qƈ未进行物理排序,所以效率较高?BR>但要注意Q在打开记录集之前必d记录集的CursorLocation属性设|ؓadUseClientQ如上例所C。Sort属性值在需要时随时可以修改?BR>16、事务处?BR>ADO中的事务处理也很单,只需分别在适当的位|调用Connection对象的三个方法即可,q三个方法是Q?BR>Q?Q、在事务开始时调用
pCnn->BeginTrans();
Q?Q、在事务l束q成功时调用
pCnn->CommitTrans ();
Q?Q、在事务l束q失败时调用
pCnn->RollbackTrans ();
在用事务处理时Q应量减小事务的范_卛_从事务开始到l束Q提交或回滚Q之间的旉间隔Q以便提高系l效率。需要时也可在调用BeginTrans()Ҏ之前Q先讄Connection对象的IsolationLevel属性|详细内容参见MSDN中有关ADO的技术资料?BR>三、用ADO~程常见问题解答
以下均是针对MS SQL 7.0~程时所遇问题进行讨论?BR>1、连接失败可能原?BR>Enterprise Managemer内,打开服务器的属性对话框Q在Security选项卡中Q有一个选项Authentication?BR>如果该选项是Windows NT onlyQ则你的E序所用的q接字符串就一定要包含Trusted_Connection参数Qƈ且其值必MؓyesQ如Q?BR>"Provider=SQLOLEDB;Server=888;Trusted_Connection=yes"
";Database=master;uid=lad;";
如果不按上述操作Q程序运行时q接必然p|?BR>如果Authentication选项是SQL Server and Windows NTQ则你的E序所用的q接字符串可以不包含Trusted_Connection参数Q如Q?BR>"Provider=SQLOLEDB;Server=888;Database=master;uid=lad;pwd=111;";
因ؓADOl该参数取的默认值就是noQ所以可以省略。我认ؓq是取默认值比较安全一些?BR>2、改变当前数据库的方?BR>使用Tansct-SQL中的USE语句卛_?BR>3、如何判断一个数据库是否存在
(1)、可打开master数据库中一个叫做SCHEMATA的视图,其内容列Z该服务器上所有的数据库名U?BR>(2) 、更便的Ҏ是用USE语句Q成功了存在;不成功,׃存在。例如:
try{
m_pConnect->Execute ( _bstr_t("USE INSURANCE_2002"),NULL,
adCmdText|adExecuteNoRecords );
}
catch (_com_error &e)
{
blSuccess=FALSE;
CString str="数据库INSURANCE_2002不存在!\n";
str+=e.Description();
::MessageBox(NULL,str,"警告",MB_OK | MB_ICONWARNING);
}
4、判断一个表是否存在
Q?Q、同样判断一个表是否存在Q也可以用是否成功地打开它来判断Q十分方便,例如Q?BR> try{
m_pRecordset->Open(_variant_t("mytable"),
_variant_t((IDispatch *)m_pConnection,true), adOpenKeyset,
adLockOptimistic, adCmdTable);
}
catch (_com_error &e)
{
::MessageBox(NULL,"该表不存在?,"提示",MB_OK | MB_ICONWARNING);
}
(2)、要不然可以采用ȝ一点的办法Q就是在MS-SQL服务器上的每个数据库中都有一个名为sysobjects的表Q查看此表的内容即知指定的表是否在该数据库中?BR>(3)、同P每个数据库中都有一个名为TABLES的视?View)Q查看此视图的内容即知指定的表是否在该数据库中?BR>5、类型{换问?BR>Q?Q、类型VARIANT_BOOL
cdVARIANT_BOOL{h于shortcd。The VARIANT_BOOL is equivalent to short. see it's definition below:
typdef short VARIANT_BOOL
Q?Q、_com_ptr_tcȝcd转换
_ConnectionPtr可以自动转换成IDspatch*cdQ这是因为_ConnectionPtr实际上是_com_ptr_tcȝ一个实例,而这个类有此cd转换函数?BR>同理Q_RecordsetPtr和_CommandPtr也都可以q样转换?BR>Q?Q、_bstr_t和_variant_tc?BR>在ADO~程Ӟ_bstr_t和_variant_tq两个类很有用,省去了许多BSTR和VARIANTcd转换的麻烦?BR>6、打开记录集时的问?BR>在打开记录集时Q在调用Recordset的OpenҎӞ其最后一个参数里一定不能包含adAsyncExecuteQ否则将因ؓ是异步操作,在读取数据时无法d数据?BR>7、异常处理问?BR>Ҏ有调用ADO的语句一定要用try和catch语句捕捉异常Q否则在发生异常ӞE序会异帔R出?BR>8、用SafeArray问题
在初学用中Q我NC个伤脑筋的问题,一定要注意Q?BR>在定义了SAFEARRAY的指针后Q如果打重复用多ơ,则在中间可以调用::SafeArrayDestroyData释放数据Q但决不能调?:SafeArrayDestroyDescriptorQ否则必然出错,即调用SafeArrayCreate也不行。例如:
SAFEARRAY *psa;
......
//When the data are no longer to be used:
::SafeArrayDestroyData( psa);
我分析在定义psa指针Ӟ一个SAFEARRAY的实例(也就是SAFEARRAY描述W)也同时被自动建立了。但是只要一调用::SafeArrayDestroyDescriptorQ描q符p销毁了?BR>所以我认ؓ::SafeArrayDestroyDescriptor可以Ҏ׃调用Q即使调用也必须在最后调用?BR>9、重复用命令对象问?BR>一个命令对象如果要重复使用多次Q尤其是带参数的命oQ,则在W一ơ执行之前,应将它的Prepared属性设|ؓTRUE。这样会使第一ơ执行减慢,但却可以使以后的执行全部加快?BR>10、绑定字W串型字D问?BR>如果要绑定的字段是字W串cdQ则对应的字W数l的元素个数一定要比字D长度大2Q比如m_szau_fname[22]Q其l定的字Dau_fname的长度实际是20Q,不这L定就会失败?BR>11、用AppendChunk的问?BR>当用AddNewҎ刚刚向记录集内添加一个新记录之后Q不能首先向一个长数据字段QimagecdQ写入数据,必须先向其他字段写入q数据之后,才能调用AppendChunk写该字段Q否则出错。也是_AppendChunk不能紧接在AddNew之后。另外,写入其他字段后还必须紧接着调用AppendChunkQ而不能调用记录集的UpdateҎ后,才调用AppendChunkQ否则调用AppendChunk时也会出错。换句话_是必须AppendChunk在前QUpdate在后。因而这个时候就不能使用带参数的AddNew了,因ؓ带参数的AddNew会自动调用记录集的UpdateQ所以AppendChunkp到Update的后面了Q就只有出错了!因此Q这时应该用不带参数的AddNew?BR>我推这可能是MS SQL 7.0的问题,在MS SQL 2000中则不存在这些问题,但是AppendChunk仍然不能在Update之后?BR>四、小l?BR>一般情况下QConnection和Command的Execute用于执行不生记录集的命令,而Recordset的Open用于产生一个记录集Q当然也不是l对的。特别Command主要是用于执行参数化的命令,可以直接由Command对象执行Q也可以Command对象传递给Recordset的Open?BR>本文中的代码片断均在VC++ 6.0、Windows NT 4.0 SP6和MS SQL 7.0中调试通过。相信您读过之后Q编写简单的数据库程序应该没有问题了。当然要~写比较实用的、复杂一点的E序Q还需要对OLE DB、ADO以及数据库^台再多了解一点,希望您l努力,一定会很快成功的!详细参考资料请参见微YMSDN July 2000光盘或MS SQL 7.0在线文档资料QBooks onlineQ。文中难免有错误和不妥之处,敬请各位批评指正Q?FONT color=#ffffcc>www.chinai tp 采吧采吧不是|?ow er.comJuJIe
参考文献:
1?微YMSDN Library - July 2000 / Platform SDK / Data Services / Microsoft Data Access Components (MDAC) / Microsoft ActiveX Data Objects (ADO)
2?微YMS SQL 7.0在线文档资料QBooks onlineQ?--- Building SQL Server Applications / ADO and SQL Server
3?微YMS SQL 7.0在线文档资料QBooks onlineQ?--- Building SQL Server Applications / Transact ?SQL Reference
4?微YMSDN Library - July 2000 / Platform SDK / Data Services / Microsoft Data Access Components (MDAC) / Microsoft OLE DB
m_pConnection.CreateInstance(__uuidof(Connection)); try { m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\FTI.mdb", "", "", adModeUnknown ); } catch(_com_error e) { AfxMessageBox("数据?/A>q接p|!"); } m_pRecordset.CreateInstance(__uuidof(Recordset));(5) lListbox控gd控g变量m_FieldsListQ?BR>(6) 在按钮的单击事g中添加相应代码;
_bstr_t mStrSQL; CString strColName; BSTR bstrColName; long ColCount,i; Field * field = NULL; HRESULT hr; Fields * fields = NULL; LPCTSTR nameField; //打开记录集,得到字段名,q将字段名信息添加到ListBox? mStrSQL = "SELECT * FROM Images"; m_pRecordset->Open(mStrSQL, m_pConnection.GetInterfacePtr(), adOpenDynamic, adLockOptimistic, adCmdText); hr = m_pRecordset->get_Fields (&fields); //得到记录集的字段集和 if(SUCCEEDED(hr)) fields->get_Count(&ColCount); //得到记录集的字段集合中的字段的M? for(i=0;i<ColCount;i++) { fields->Item[i]->get_Name(&bstrColName); //得到记录?/中的字段? strColName=bstrColName; nameField = strColName; m_FieldsList.AddString(nameField); } if(SUCCEEDED(hr)) fields->Release();//释放指针
使用通用数据q接文gQ?.UDLQ以下简U文Ӟ来创建ADOq接Q可以和ODBC一样可视化地定义要q接的数据源Q从而实现数据访问的透明性? 1.使用UDL文g来创建ADOq接 创徏ADO的连接,首先要设|ADOq接对象的ConnectionString属性,该属性提供所要连接的数据库类型、数据所处服务器、要讉K的数据库和数据库讉K的安全认证信息。比较专业的Ҏ是在ConnectionString中直接提供以上信息,下面是访问不同类型数据源讄ConnectionString的标准: 讉KODBC数据 "Provider=MSDASQL;DSN=dsnName;UID=userName;PWD=userPassword;" 讉KORACLE数据? "Provider=MSDAORA;Data Source=serverName;User ID=userName; Password=userPassword;" 讉KMS SQL数据? "Provider=SQLOLEDB;Data Source=serverName;Initial Catalog=databaseName; User ID=userName;Password=userPassword;" 讉KACCESS 数据? "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=databaseName;User ID=userName;Password=userPassword;" 上述的连接属性设|标准随着数据源的cd不同而变化,软g用户常常不习惯这U设|方式,都希望有可视化的数据源设|方法。ؓ此Microsoft提供了通用数据q接文gQ?UDLQ来建立和测试ADOq接属性。ADOq接对象可以很方便地使用UDL文g来连接数据源Q下面例子用my_data1.udl来创建ADOq接? _ConnectionPtr m_pDBConn; m_pDBConn.CreateInstance(__uuidof(Connection)); m_pDBConn->ConnectionString ="File Name=c:\mydir\my_data1.udl"; //注意Qname=cQ等号两边不能有I格 m_pDBConn->Open("","","",NULL); q样一来无论数据源如何变化Q在软g中都可以用统一的方法编E。当数据源改变时Q只要双ȝ应的udl文g卛_可视化地讄数据源,无需更改软g? 因ؓADO是COM接口Qؓ了Y件的可靠性,打开ADOq接Ӟ可以加入异常处理代码? try{ m_pDBConn->Open("","","",NULL); }catch(_com_error &e){ //处理异常的代? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . m_pDBConn=NULL; } 因ؓ_ConnectionPtr m_pDBConn是智能指针,应在处理异常代码时将指针设ؓNULL后将自动引用计数降?? 如果不出现异常,只要在用完m_pDBConnQ只要引用CloseҎ卛_? 2.创徏你所需的UDL文g 在你所惛_建UDL文g的目录中单击右键Q选择从菜?新徏|Microsoft 数据q接Q然后将新创建的UDL文g更改Z所希望的文件名Q?UDL扩展名不能改变)? |
|
1. 生成应用E序框架q初始化OLE/COM库环? 创徏一个标准的MFC AppWizard(exe)应用E序Q然后在使用ADO数据?/A>的InitInstance函数中初始化OLE/COM库(因ؓADO库是一个COM DLL库)?BR>本例为: |
BOOL CAdotestDlg::OnInitDialog() { ::CoInitialize(NULL); //初始化OLE/COM库环? } |
E序最后要调用 ::CoUninitialize()Q?/释放E序占用的COM 资源?BR>另外Q?/TD> |
m_pRecordset->Close(); 注意Q!Q不要多ơ关闭!Q!Q!Q!Q!Q!Q? m_pConnection->Close(); m_pRecordset = NULL; m_pConnection = NULL; |
2. 引入ADO?A target=_blank>文g 使用ADO前必d工程的stdafx.h文g最后用直接引入W号Qimport引入ADO?A target=_blank>文gQ以使编译器能正编译。代码如下: #import "C:\Program Files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF") ADOcȝ定义是作ZU资源存储在ADO DLL(msado15.dllQ中Q在其内部称为类型库。类型库描述了自L口,以及CQ+使用的COM vtable接口。当使用Qimport指oӞ在运行时Visual CQ+需要从ADO DLL中读取这个类型库Qƈ以此创徏一lCQ+?A target=_blank>文g。这些头文gh.tli ?tlh扩展名,读者可以在目的目录下扑ֈq两?A target=_blank>文g。在CQ+E序代码中调用的ADOc要在这?A target=_blank>文g中定义? E序的第三行指示ADO对象不用名U空间。在有些应用E序中,׃应用E序中的对象与ADO中的对象之间可能会出现命名冲H,所以有必要使用名称I间。如果要使用名称I间Q则可把W三?A target=_blank>E序修改为: rename_namespace("AdoNS")。第四行代码ADO中的EOF(文gl束)更名为adoEOFQ以避免与定义了自己的EOF的其他库冲突? 3Q利用智能指针进?A target=_blank>数据?/A>操作 在CaboutDlg?A target=_blank>文g中定义两个ADO指针cd?q在对话框中加入一个ListCtrl?BR> |
class CAdotestDlg : public CDialog { _ConnectionPtr m_pConnection; _RecordsetPtr m_pRecordset; ClistCtrl m_List; ...... } |
ADO库包含三个智能指?_ConnectionPtr、_CommandPtr和_RecordsetPtr?BR> _ConnectionPtr通常被用来创Z个数据连接或执行一条不q回Ml果的SQL语句Q如一个存储过E?BR>_CommandPtrq回一个记录集。它提供了一U简单的Ҏ来执行返回记录集的存储过E和SQL语句。在使用_CommandPtr接口Ӟ可以利用全局_ConnectionPtr接口Q也可以在_CommandPtr接口里直接用连接串。_RecordsetPtr是一个记录集对象。与以上两种对象相比Q它对记录集提供了更多的控制功能Q如记录锁定、游标控制等? 在用ADOE序的事件响应中OnButton1加入以下代码: |
void CAdotestDlg::OnButton1() { m_List.ResetContent(); m_pConnection.CreateInstance(_uuidof(Connection)); //初始化Connection指针 m_pRecordset.CreateInstance(_uuidof(Recordset));//初始化Recordset指针 try { m_pConnection->Open("DSN=ADOTest","","",0); //q接叫作ADOTest的ODBC数据? //注意Q这是连接不需要用户ID或密码的open 函数 // 否则形式?->Open("DSN=test;uid=sa;pwd=123;","","",0); // 执行SQL语句得到一个记录集把其指针赋值给m_pRecordset CString strSql="select * from middle"; BSTR bstrSQL = strSql.AllocSysString(); m_pRecordset->Open(bstrSQL,(IDispatch*)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText); //adOpenDynamicQ动?adLockOptimistic乐观锁?adCmdTextQ文本查询语? while(!m_pRecordset->adoEOF)//遍历所有记? { //取纪录字D值方式之一 _variant_t TheValue; //VARIANT数据cd TheValue = m_pRecordset->GetCollect("BIG_NAME");//得到字段BIG_NAME的? if(TheValue.vt!=VT_NULL) m_List.AddString((char*)_bstr_t(TheValue)); //该值加入到列表控g? //取纪录字D值方式之? // _bstr_t TheValue1=m_pRecordset->Fields->GetItem("BIG_NAME")->Value; // CString temp=TheValue1.copy(); // m_List.AddString(temp); //数据cd转换 _variant_t vUsername,vBirthday,vID,vOld; TRACE("id:%d,姓名:%s,q龄:%d,生日:%s\r\n", vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday); m_pRecordset->MoveNext();//转到下一条纪? } m_pRecordset->Close(); m_pConnection->Close(); } catch (_com_error e)//异常处理 { AfxMessageBox(e.ErrorMessage()); } m_pRecordset->Close(); //注意Q!Q不要多ơ关闭!Q!Q否则会出错 m_pConnection->Close(); m_pRecordset = NULL; m_pConnection = NULL; } |
E序中通过_variant_t和_bstr_t转换COM对象和CQ+cd的数? _variant_tcd装了OLE自治VARIANT数据cd。在C++中用_variant_tc要比直接用VARIANT数据cdҎ得多? 好,~译后该E序pq行了,但记住运行前要创Z个叫ADOTest的ODBC数据源。该E序把表middle中的BIG_NAME字段值显C在列表控g中?BR> 4Q执行SQL命oq取得结果记录集 Z取得l果记录集,我们定义一个指向Recordset对象的指?_RecordsetPtr m_pRecordset; qؓ其创建Recordset对象的实? m_pRecordset.CreateInstance("ADODB.Recordset"); SQL命o的执行可以采用多UŞ式,下面我们一q行阐述?BR> (1)利用Connection对象的ExecuteҎ执行SQL命o ExecuteҎ的原型如下所C? |
_RecordsetPtr Connection15::Execute ( _bstr_t CommandText, VARIANT * RecordsAffected, long Options ) 其中CommandText是命令字Ԍ通常是SQL命o? 参数RecordsAffected是操作完成后所影响的行? 参数Options表示CommandText中内容的cdQOptions可以取如下g一Q? adCmdText:表明CommandText是文本命? adCmdTable:表明CommandText是一个表? adCmdProc:表明CommandText是一个存储过E? adCmdUnknown:未知 Execute执行完后q回一个指向记录集的指针,下面我们l出具体代码q作说明? _variant_t RecordsAffected; ///执行SQL命oQCREATE TABLE创徏表格users,users包含四个字段:整ŞID,字符串username,整Şold,日期型birthday m_pConnection->Execute("CREATE TABLE users(ID INTEGER,username TEXT,old INTEGER,birthday DATETIME)", &RecordsAffected, adCmdText); ///往表格里面d记录 m_pConnection->Execute("INSERT INTO users(ID,username,old,birthday) VALUES (1, ''''Washington'''',25,''''1970/1/1'''')",&RecordsAffected,adCmdText); ///所有记录old字段的值加一 m_pConnection->Execute("UPDATE users SET old = old+1",&RecordsAffected,adCmdText); ///执行SQLl计命o得到包含记录条数的记录集 m_pRecordset = m_pConnection->Execute("SELECT COUNT(*) FROM users",&RecordsAffected,adCmdText); _variant_t vIndex = (long)0; _variant_t vCount = m_pRecordset->GetCollect(vIndex);///取得W一个字D늚值放入vCount变量 上两句可以写成?_variant_t vCount = m_pRecordset->GetCollect((_variant_t)((long)0)); m_pRecordset->Close();///关闭记录? CString message; message.Format("共有%d条记?,vCount.lVal); AfxMessageBox(message);///昄当前记录条数 |
(2)利用Command对象来执行SQL命o |
_CommandPtr m_pCommand;
m_pCommand.CreateInstance("ADODB.Command");
_variant_t vNULL;
vNULL.vt = VT_ERROR;
vNULL.scode = DISP_E_PARAMNOTFOUND;///定义为无参数
m_pCommand->ActiveConnection = m_pConnection;///非常关键的一句,徏立的q接赋值给?
m_pCommand->CommandText = "SELECT * FROM users";///命o字串
m_pRecordset = m_pCommand->Execute(&vNULL,&vNULL,adCmdText);///执行命oQ取得记录集 |
在这D代码中我们只是用Command对象来执行了SELECT查询语句QCommand对象在进行存储过E的调用中能真正体现它的作用。下ơ我们将详细介绍? (3)直接用Recordset对象q行查询取得记录? 实例—?/TD> |
void CGmsaDlg::OnDBSelect() { // TODO: Add your control notification handler code here _RecordsetPtr Rs1; //定义Recordset对象 _bstr_t Connect("DSN=GMS;UID=sa;PWD=;");//定义q接字符? _bstr_t Source ("SELECT count(*) FROM buaa.mdb010"); //要执行的SQL语句 ::CoInitialize(NULL); //初始化Rs1对象 HRESUL hr = Rs1.CreateInstance( __uuidof( Recordset ) ); //省略对返回值hr的判? Rs1->Open( Source, Connect, adOpenForwardOnly, adLockReadOnly, -1 ); _variant_t temp=Rs1->GetCollect(_variant_t((long)0)); CString strTemp=(char* )(_bstr_t)temp; MessageBox("OK!"+strTemp); } 例如 m_pRecordset->Open("SELECT * FROM users", _variant_t((IDispatch *)m_pConnection,true), adOpenStatic, adLockOptimistic, adCmdText); OpenҎ的原型是q样? HRESULT Recordset15::Open ( const _variant_t & Source, const _variant_t & ActiveConnection, enum CursorTypeEnum CursorType, enum LockTypeEnum LockType, long Options ) 其中Q? ①Source是数据查?A target=_blank>字符? ②ActiveConnection是已l徏立好的连接(我们需要用Connection对象指针来构造一个_variant_t对象) ③CursorType光标cdQ它可以是以下g一,Lq个枚Dl构: enum CursorTypeEnum { adOpenUnspecified = -1,///不作特别指定 adOpenForwardOnly = 0,///前滚静态光标。这U光标只能向前浏览记录集Q比如用MoveNext向前滚动,q种方式可以提高览速度。但诸如BookMark,RecordCount,AbsolutePosition,AbsolutePage都不能? adOpenKeyset = 1,///采用q种光标的记录集看不到其它用L新增、删除操作,但对于更新原有记录的操作对你是可见的? adOpenDynamic = 2,///动态光标。所?A target=_blank>数据?/A>的操作都会立卛_各用戯录集上反应出来? adOpenStatic = 3///静态光标。它Z的记录集产生一个静态备份,但其它用L新增、删除、更新操作对你的记录集来说是不可见的? }; ④LockType锁定cdQ它可以是以下g一Q请看如下枚丄构: enum LockTypeEnum { adLockUnspecified = -1,///未指? adLockReadOnly = 1,///只读记录? adLockPessimistic = 2,悲观锁定方式。数据在更新旉定其它所有动作,q是最安全的锁定机? adLockOptimistic = 3,乐观锁定方式。只有在你调用UpdateҎ时才锁定记录。在此之前仍然可以做数据的更新、插入、删除等动作 adLockBatchOptimistic = 4Q乐观分Ҏ新。编辑时记录不会锁定Q更攏V插入及删除是在批处理模式下完成? }; ⑤Options可以取如下g一Q? adCmdText:表明CommandText是文本命? adCmdTable:表明CommandText是一个表? adCmdProc:表明CommandText是一个存储过E? adCmdUnknown:未知 |
5. 记录集的遍历、更?BR> Ҏ我们刚才通过执行SQL命o建立好的users表,它包含四个字D?ID,username,old,birthday 以下的代码实玎ͼ打开记录集,遍历所有记录,删除W一条记录,d三条记录Q移动光标到W二条记录, 更改其年龄,保存?A target=_blank>数据?/A>?/TD> |
_variant_t vUsername,vBirthday,vID,vOld; _RecordsetPtr m_pRecordset; m_pRecordset.CreateInstance("ADODB.Recordset"); m_pRecordset->Open("SELECT * FROM users", _variant_t((IDispatch*)m_pConnection,true), adOpenStatic, adLockOptimistic, adCmdText); while(!m_pRecordset->adoEOF) { vID = m_pRecordset->GetCollect(_variant_t((long)0));///取得W?列的??开始计敎ͼ ///你也可以直接l出列的名称Q如下一? vUsername = m_pRecordset->GetCollect("username");///取得username字段的? vOld = m_pRecordset->GetCollect("old"); vBirthday = m_pRecordset->GetCollect("birthday"); ///在DEBUG方式下的OUTPUTH口输出记录集中的记? if(vID.vt != VT_NULL && vUsername.vt != VT_NULL && vOld.vt != VT_NULL && vBirthday.vt != VT_NULL) TRACE("id:%d,姓名:%s,q龄:%d,生日:%s\r\n", vID.lVal, (LPCTSTR)(_bstr_t)vUsername, vOld.lVal, (LPCTSTR)(_bstr_t)vBirthday); m_pRecordset->MoveNext();///Ud下一条记? } m_pRecordset->MoveFirst();///Ud首条记录 m_pRecordset->Delete(adAffectCurrent);///删除当前记录 ///d三条新记录ƈ赋? for(int i=0;i<3;i++) { m_pRecordset->AddNew();///d新记? m_pRecordset->PutCollect("ID",_variant_t((long)(i+10))); m_pRecordset->PutCollect("username",_variant_t("叶利?)); m_pRecordset->PutCollect("old",_variant_t((long)71)); m_pRecordset->PutCollect("birthday",_variant_t("1930-3-15")); } m_pRecordset->Move(1,_variant_t((long)adBookmarkFirst));///从第一条记录往下移动一条记?即移动到W二条记录处 m_pRecordset->PutCollect(_variant_t("old"),_variant_t((long)45));///修改其年? m_pRecordset->Update();///保存到库? |
备注Q多ơ查询可把查询过E做成一个函数ExecuteSQL让m_pRecordset获得q接指针m_pConnection查询l果 |
void ExecuteSQL(_ConnectionPtr m_pConnection, _RecordsetPtr m_pRecordset,CString strSql) { //执行Select 语句 BSTR bstrSQL = strSql.AllocSysString(); try { m_pRecordset->Open(bstrSQL,(IDispatch*)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText); //adOpenDynamicQ动? adLockOptimistic乐观锁? adCmdTextQ文本查询语? } catch(_com_error error) { CString errorMessage; errorMessage.Format("%s",(LPTSTR)error.Description()); AfxMessageBox(errorMessage); } } //出错处理Q? 3127——没有找到目标表 3092——目标表已经存在 例如Q? catch(const _com_error e) { AfxMessageBox(e.Description()); long errorCode=e.WCode(); if(3127==errorCode) AfxMessageBox("表不存在"); if(3092==errorCode) AfxMessageBox("表已l存?); return FALSE; } |
(use serverName\instanceName as Data Source to use an specifik SQLServer instance, only SQLServer2000)
(DBMSSOCN=TCP/IP instead of Named Pipes, at the end of the Data Source is the port to use (1433 is the default))
(use serverName\instanceName as Data Source to use an specifik SQLServer instance, only SQLServer2000)
(DBMSSOCN=TCP/IP instead of Named Pipes, at the end of the Data Source is the port to use (1433 is the default))
C#:
using System.Data.SqlClient;
SqlConnection oSQLConn = new SqlConnection();
oSQLConn.ConnectionString="my connectionstring";
oSQLConn.Open();
Want to learn data shaping? Check out 4GuyfFromRolla's great article about Data Shaping >>
Name | Network library |
dbnmpntw | Win32 Named Pipes |
dbmssocn | Win32 Winsock TCP/IP |
dbmsspxn | Win32 SPX/IPX |
dbmsvinn | Win32 Banyan Vines |
dbmsrpcn | Win32 Multi-Protocol (Windows RPC) |
Name | Default | Description |
---|---|---|
Application Name | The name of the application, or '.Net SqlClient Data Provider' if no application name is provided. | |
AttachDBFilename -or- extended properties -or- Initial File Name |
The name of the primary file, including the full path name, of an attachable database. The database name must be specified with the keyword 'database'. | |
Connect Timeout -or- Connection Timeout |
15 | The length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error. |
Connection Lifetime | 0 | When a connection is returned to the pool, its creation time is compared with the current time, and the connection is destroyed if that time span (in seconds) exceeds the value specified by connection lifetime. Useful in clustered configurations to force load balancing between a running server and a server just brought on-line. |
Connection Reset | 'true' | Determines whether the database connection is reset when being removed from the pool. Setting to 'false' avoids making an additional server round-trip when obtaining a connection, but the programmer must be aware that the connection state is not being reset. |
Current Language | The SQL Server Language record name. | |
Data Source -or- Server -or- Address -or- Addr -or- Network Address |
The name or network address of the instance of SQL Server to which to connect. | |
Enlist | 'true' | When true, the pooler automatically enlists the connection in the creation thread's current transaction context. |
Initial Catalog -or- Database |
The name of the database. | |
Integrated Security -or- Trusted_Connection |
'false' | Whether the connection is to be a secure connection or not. Recognized values are 'true', 'false', and 'sspi', which is equivalent to 'true'. |
Max Pool Size | 100 | The maximum number of connections allowed in the pool. |
Min Pool Size | 0 | The minimum number of connections allowed in the pool. |
Network Library -or- Net |
'dbmssocn' | The network library used to establish a connection to an instance of SQL Server. Supported values include dbnmpntw (Named Pipes), dbmsrpcn (Multiprotocol), dbmsadsn (Apple Talk), dbmsgnet (VIA), dbmsipcn (Shared Memory) and dbmsspxn (IPX/SPX), and dbmssocn (TCP/IP). The corresponding network DLL must be installed on the system to which you connect. If you do not specify a network and you use a local server (for example, "." or "(local)"), shared memory is used. |
Packet Size | 8192 | Size in bytes of the network packets used to communicate with an instance of SQL Server. |
Password -or- Pwd |
The password for the SQL Server account logging on. | |
Persist Security Info | 'false' | When set to 'false', security-sensitive information, such as the password, is not returned as part of the connection if the connection is open or has ever been in an open state. Resetting the connection string resets all connection string values including the password. |
Pooling | 'true' | When true, the SQLConnection object is drawn from the appropriate pool, or if necessary, is created and added to the appropriate pool. |
User ID | The SQL Server login account. | |
Workstation ID | the local computer name | The name of the workstation connecting to SQL Server. |
This one's from Microsoft, the following are from Oracle
This one works only with Oracle 8i release 3 or later
C#:
using System.Data.OracleClient;
OracleConnection oOracleConn = new OracleConnection();
oOracleConn.ConnectionString = "my connectionstring";
oOracleConn.Open();
Read more at Core Lab and the product page.
Want to learn data shaping? Check out 4GuyfFromRolla's great article about Data Shaping >>
This one is used with eInfoDesigns dbProvider, an add-on to .NET
C#:
using eInfoDesigns.dbProvider.MySqlClient;
MySqlConnection oMySqlConn = new MySqlConnection();
oMySqlConn.ConnectionString = "my connectionstring";
oMySqlConn.Open();
This is a freeware ADO.Net data provider from SevenObjects
Read more at Core Lab and the product page.
Read more about this driver: Easysoft ODBC-Interbase driver >>
This driver are provided by DataDirect Technologies >> (formerly Intersolv)
Read more about SIBPROvider >>
Do you know a userguide for Sybase System 11, 12, 12.5? E-mail the URL to connectionstrings.com now!! >>
Note! The two double quota following the DSN parameter at the end are escaped quotas (VB syntax), you may have to change this to your language specific escape syntax. The empty DSN parameter is indeed critical as not including it will result in error 7778.
Read more in the ASA User Guide >>
Note that you must create a Data Source .IDS file using the Sybase Data Administrator. These .IDS files resemble ODBC DSNs.
This one works only from Open Client 12.5 where the server port number feature works,燼llowing fully qualified connection strings to be used without defining燼ny .IDS Data Source files.
Read more at Core Lab and the product page.
"HDR=Yes;" indicates that the first row contains columnnames, not data
"IMEX=1;" tells the driver to always read "intermixed" data columns as text
TIP! SQL syntax: "SELECT * FROM [sheet1$]" - i.e. worksheet name followed by a "$" and wrapped in "[" "]" brackets.
"HDR=Yes;" indicates that the first row contains columnnames, not data
Read more (Microsoft msdn) >>
"Collate=Machine" is the default setting, for other settings check the list of supported collating sequences >>
Pervasive ODBC info >>
Pervasive OLE DB info >>