CRecordSet, CDatabase dynamisch ?
-
So, bevor ich noch wahnsinnig werde und meinen Laptop aus dem Fenster werfe, hier
der letzte Versuch. Problemstellung wie oben angedeutet; ich möchte diverse
Recordsets ( die an sich alle perfekt funktionieren ) über eine allgemeine
CRecordSetklasse abfackeln; dies scheint bei weitem nicht so einfach zu sein, wie ich mir das wohl etwas blauäugig gedacht habe. Orientiert habe ich mich an den spärlichen Microsoft Beispielen dynabind, catalog etc. - funktioniert aber trotzdem nicht.
Gedacht habe ich mir das folgendermaßen, in der Open Funktion von CRecordSet baue ich mir eine verkettete Liste mit den einzelnen Spalten auf. Diese Informationen hole ich mir über CColumns ( wie in dynabind ) - das funktioniert ausnahmsweise perfekt.
Eigentlich ( dachte ich zumindest ) brauche ich doch dann nur in DoFieldExchange über die einzelen Elemente aus meiner verketteten Liste zu gehen und je nach Typ die einzelnen RFX_Text etc. aufrufen. Und ab jetzt geht aber praktisch gar nichts mehr; egal was ich mache, irgendwann stürzt die Funktion hier immer ab, entweder bei m_nOperation==::AllocCache oder m_nOperation==::BindFieldToColumn. Das Problem scheint irgendwie zu sein, daß die MFC im Hintergrund mit ihren eigenen Buffern arbeitet, die logischerweise gar nicht angelegt sind. Wo liegt
hier mein Denkfehler ?Nachfolgend noch die wahrscheinlichen Fehlerquellen,
bin für jeden Tip dankbarvoid CKontoRecordSet::Move (long lRows, WORD nType) { CColumns Spalten; int nSpalten = 0; if ( !m_ISFieldsLoaded ) { Spalten.m_pDatabase = m_pDatabase; Spalten.m_strTableNameParam = "KONTEN"; Spalten.Open (); while ( !Spalten.IsEOF() ) { // nSpalten++; CMyODBCFieldInfo *pCMyODBCFieldInfo = new MyODBCFieldInfo; pCMyODBCFieldInfo->Name = Spalten.m_strColumnName; pCMyODBCFieldInfo->nSQLType = Spalten.m_nDataType; pCMyODBCFieldInfo->nPrecision = Spalten.m_lPrecision; pCMyODBCFieldInfo->nScale = Spalten.m_nScale; pCMyODBCFieldInfo->ISNullable = Spalten.m_nNullable; pCMyODBCFieldInfo->pValueCStr = 0; pCMyODBCFieldInfo->pValueCOleDateTime = 0; switch ( pCMyODBCFieldInfo->nSQLType ) { case SQL_CHAR : case SQL_VARCHAR : case SQL_NUMERIC : case SQL_DECIMAL : case SQL_DOUBLE : case SQL_INTEGER : case SQL_BINARY : case SQL_VARBINARY : case SQL_LONGVARBINARY : case SQL_SMALLINT : case SQL_FLOAT : case SQL_REAL : case SQL_TINYINT : case SQL_BIT : case SQL_GUID : case SQL_BIGINT: case SQL_DATE : case SQL_TIME : case SQL_LONGVARCHAR : pCMyODBCFieldInfo->pValueCStr = new CString ('\x00', pCMyODBCFieldInfo->nPrecision + 1); break; case SQL_TIMESTAMP : pCMyODBCFieldInfo->pValueCOleDateTime = new COleDateTime; break; } m_ListeFields.AddTail (pCMyODBCFieldInfo); // Spalten.MoveNext (); } Spalten.Close (); m_nFields = nSpalten; m_ISFieldsLoaded = TRUE; } CRecordset::Move (lRows, nType); }
void CKontoRecordSet::DoFieldExchange (CFieldExchange *pFX) { CMyODBCFieldInfo *pCMyODBCFieldInfo; POSITION Pos; pFX->SetFieldType (CFieldExchange::outputColumn); for ( Pos = m_ListeFields.GetHeadPosition (); Pos; ) { pCMyODBCFieldInfo = (CMyODBCFieldInfo *) m_ListeFields.GetNext (Pos); switch ( pCMyODBCFieldInfo->nSQLType ) { case SQL_CHAR : case SQL_VARCHAR : case SQL_NUMERIC : case SQL_DECIMAL : case SQL_BINARY : case SQL_VARBINARY : case SQL_LONGVARBINARY : case SQL_SMALLINT : case SQL_FLOAT : case SQL_REAL : case SQL_TINYINT : case SQL_BIT : case SQL_GUID : case SQL_BIGINT: case SQL_DATE : case SQL_TIME : case SQL_LONGVARCHAR : RFX_Text (pFX, pCMyODBCFieldInfo->Name.GetBuffer (1), *(pCMyODBCFieldInfo->pValueCStr)); break; case SQL_TIMESTAMP : RFX_Date (pFX, pCMyODBCFieldInfo->Name.GetBuffer (1), *(pCMyODBCFieldInfo->pValueCOleDateTime)); break; } } }
-
ich hab das mal so gemacht:
void CDepot::ImplementColumns() { //Öffnet aktuelle Datenbank mit anderen Spalten extern View* View_Handle; if (View_Handle != NULL && View_Handle->Table_Name.GetSize() > 0) { if (!View_Handle->Table_Name[View_Handle->step_run + 1].IsEmpty()) { int lauf = 0; //übergibt Zeiger auf CColumns-Objekt und bindet Datenbank an m_act_db.Open(NULL, FALSE, FALSE, (_T("ODBC;DSN=Database")), TRUE); CColumns* m_DB_Col_end = new CColumns(&m_act_db); m_DB_Col_end->m_strTableNameParam = View_Handle->Table_Name[View_Handle->step_run + 1]; m_DB_Col_end->Open(CRecordset::snapshot); m_DB_Col_end->MoveFirst(); //überträgt Spaltennamen in CArray-Objekt while (!m_DB_Col_end->IsEOF()) { m_actCol_end.Add(m_DB_Col_end->m_strColumnName); m_actCol_end[lauf].Insert(0, '['); //für Verarbeitung der SQL-Befehle m_actCol_end[lauf].Insert(m_actCol_end[lauf].GetLength(), ']'); m_typCol_end.Add(m_DB_Col_end->m_strTypeName); m_DB_Col_end->MoveNext(); lauf++; } BuildValueLists(); //SaveArrayToFile(); delete m_DB_Col_end; } } } void CDepot::BuildValueLists() { size = m_actCol_end.GetSize(); int lauf2 = 0; int lauf = 0; while (lauf2 < size) { m_dblCol_end.Add(lauf); lauf++; lauf2++; } }
so hats bei mir geklappt, über die diversen arrays kannst du dann die spalten und werte ansprechen.
table_name sind die entsprechenden tabellennamen.