Tutorial VC++ 6.0 und Oracle



  • @LordTerra:
    Ich würde dir ADO empfehlen, nicht weil ADO irgendwie "mächtiger" wäre, sondern weil ADO viel einfacher ist, vor allem für Einsteiger. Plus du findest ca. 100x mehr Beispiele zum Thema ADO als zu ODBC.

    Mittlerweile, also seit ADO .NET so gross geworden ist, findet man immer weniger Beispiele für ADO (ohne .NET), aber viel ist gleich oder fast gleich geblieben. Und auf C++ Seiten findet man immernoch ADO (ohne .NET) Code, da die wenigsten C++/CLI verwenden wollen, nur um mit ADO .NET arbeiten zu können.



  • so ok sagen wir ma ch will das ado ausprobieren ...

    dann hat mir der cpp_junky ja schon nen link geschickt wo nen beispiel drin ist ...
    aber da ist ne dll verlinkt die bei dem beispiel mal wieder net bei ist ... (msado15.dll)
    wo bekomm ich diese dll ? und ma doof gefragt : wie binde ich die ein ? das letzte mal als ich das versucht hab hat das nämlich net geklappt und wenn ihr wisst wie das geht wäre ne kurze anleitung echt nett 🙂



  • ok ich denke das hab ich selbst hin bekommen ...
    aber wie bau ich nun mit dem ado ne verbindung zu ner oracle db auf ???

    also das was mir grad kopfzerbrechen bereitet:

    bei der oracle variante per odbc hab ich ja nen odbc treiber installiert und dann per hand nen objekt unter: start -> einstellung- > systemsteuerung -> verwaltung -> datenquellen (odbc) erstellt (ArgusDB) und auf dieses objekt hab ich dann noch nen dsn erzeugt und daraufbezieh ich mich ja in meinem connect über odbc ... nur wie geht das unter ado bzw muss ich mich da auf die selbe datei beziehen ? also da bin ich grad am grübeln...



  • Für ADO musst du dir nur die entsprechende Syntax für den Connection-String suchen. Sollte im Netz recht einfach zu finden sein.
    DSN brauchst du keinen. (Ich mag die ODBC DSN Einträge auch nicht, finde das persönlich doof wenn ein Programm erfordert dass ich in meinem System irgendwas erstelle/einstelle damit es geht)



  • hmmm ok dann guck ich da mal ob ich was finde ...
    für den moment hab ich halt den dsn eintrag genutzt ...
    der geht ja auch unter ado ...

    ich hab da aber nen problem mit dem updaten von daten ...
    und zwar ist in dem code beispiel von codeproject zwar ne update funktion drin aber irgendwie funktioniert die bei mir nicht ...

    also folgendes: ich geh in meiner updatefunktion so vor: ich selectiere mir die entsprechende zeile die ich updaten will -> überschreibe das feld mit dem neuen wert -> und sage pRecordset->UpdateBatch(adAffectAll); -> und schliesse das recordset

    ^^ das ist laut testprogramm eigentlich alles was ich machen muss
    nur irgendwie funktioniert das nicht ...
    also wenn ich mir
    pRecordset->Fields->GetItem((_variant_t)feld)->Value und (_bstr_t) wert;
    ausgeben lasse bekomm ich auch genau das was ich haben will
    wenn ich jetzt aber sage:
    pRecordset->Fields->GetItem((_variant_t)feld)->Value = (_bstr_t) wert;
    und
    pRecordset->UpdateBatch(adAffectAll);
    passiert gar nix ...

    wieso ist das so ? bzw was mach ich da falsch ?



  • ah fehler gefunden ...

    pRecordset->Open ((IDispatch 😉 pCommand, vtMissing, adOpenStatic,
    adLockBatchOptimistic, adCmdUnknown);

    ^^ hatte ich vergessen ... hatte das im readonly modus geöffnet



  • ok soweit sogut ...
    eine frage hätte ich dann noch ... in dem ado test beispiel ist leider keine variante beschrieben wie man nun auch datensätze aus so nem record löschen kann ... habt ihr da noch nen beispiel parat oder kann mir wer sagen wie das geht ?



  • moin ich nochmal

    also ich hab derzeit arge probleme datensätze zu inserten ...
    das geht irgendwie nicht ...
    also ich hab derzeit nicht so richtig nen plan wie ich per ado nen insert oder nen delete machen kann ... brauche dazu bitte ne erklärung oder ne website ...



  • Entweder als SQL Statement per Execute Funktion über das Connection Objekt oder per Recordset Objekt mit AddNew bzw Delete



  • ich hab mich mal an nem insert versucht ...
    fehlermeldunge konnen net aber er führt auch nix aus ...

    aufruf:
    if(DBConnectNow()){
        DBInsertNow("INSERT INTO test (id, name) VALUES (55, 'testinsert');");
        DBCloseNow();
    }
    
    DBConnectNow():
    BOOL CACS400App::DBConnectNow(){
    	CoInitialize (NULL);
    
    	// Stablishing a connection to the datasource
    	try	{
    		HRESULT hr = m_pConn.CreateInstance (__uuidof (Connection));
    
    		if (FAILED (hr)){
    			AfxMessageBox ("Can't create intance of Connection");
    			return FALSE;
    		}
    
    		if (FAILED (m_pConn->Open (_bstr_t ("Provider=MSDAORA.1;Password=pw;User ID=system;Data Source=PROD.WORLD;Persist Security Info=True"),
    					_bstr_t (""), _bstr_t (""), adModeUnknown))){
    			AfxMessageBox ("Can't open datasource");
    			return FALSE;
    		}
    	}catch ( _com_error &e ){
    		_bstr_t bstrSource (e.Source());
    		_bstr_t bstrDescription (e.Description());
    		TRACE ( "Exception thrown for classes generated by #import" );
    		TRACE ( "\tCode = %08lx\n", e.Error ());
    		TRACE ( "\tCode meaning = %s\n", e.ErrorMessage ());
    		TRACE ( "\tSource = %s\n", (LPCTSTR) bstrSource);
    		TRACE ( "\tDescription = %s\n", (LPCTSTR) bstrDescription);
    
    		AfxMessageBox ((LPCTSTR) bstrDescription);
    		return FALSE;
    	}catch (...){
    		TRACE ( "*** Unhandled Exception ***" );
    		return FALSE;
    	}
    
    	return TRUE;		
    }
    
    DBInsertNow():
    BOOL CACS400App::DBInsertNow(CString aktion){
    	try	{
    		_CommandPtr pCommand;
    
    		HRESULT hr = pCommand.CreateInstance (__uuidof (Command));
    
    		if (FAILED (hr)){
    			AfxMessageBox ("Can't create an instance of Command");
    			return FALSE;
    		}
    		// Pointer to ADO data connection //
    		m_pConn->Execute((_bstr_t) aktion, NULL, adExecuteNoRecords);
    	} 
    	catch( _com_error &e )	{
    		_bstr_t bstrSource(e.Source());
    		_bstr_t bstrDescription(e.Description());
    		TRACE( "Exception thrown for classes generated by #import" );
    		TRACE( "\tCode = %08lx\n", e.Error());
    		TRACE( "\tCode meaning = %s\n", e.ErrorMessage());
    		TRACE( "\tSource = %s\n", (LPCTSTR) bstrSource);
    		TRACE( "\tDescription = %s\n", (LPCTSTR) bstrDescription);
    		return FALSE;		
    	}catch (...){
    		TRACE ( "*** Unhandled Exception ***" );
    		return FALSE;		
    	}
    	return TRUE;		
    }
    
    DBCloseNow():
    void CACS400App::DBCloseNow(){
    	if ( (m_pConn->State & adStateOpen) == adStateOpen)
    		m_pConn->Close();
    
    	CoUninitialize();
    }
    

    *edit*: ok es scheint so als ob der insert eigentlich geht, aber irgendwie bekommt mein programm von der db die fehlermeldung: ORA-00911: invalid character
    nur frag ich mich wieso das so ist ... hat jemand ne idee ?

    mfg LT



  • - Du könntest mal mit dem Debugger durchgehen.
    - Du könntest den Netzwerkverkehr zum Datenbankserver mit Wireshark mitschneiden und schauen, ob der das Statement überhaupt absetzt.



  • wie ich geschrieben hab: der setzt den ab aber ich bekomm ne fehlermeldung: ora-00911... und das versteh ich nicht ...
    ich hab in meiner tabelle genau 2 felder:
    feld id mit integer als typ
    feld name mit vchar2 als typ

    wieso bekomm ich da invalid character zurück wenn ich 55 und 'testinsert' reinschreiben will?



  • und gleich noch ne frage:

    mir ist aufgefallen das wenn ich folgenden connectionstring benutze meine updatefunktion nicht funktioniert ...
    wieso ist das so ???

    Mit diesem open funktioniert die Update Funktion:

    if (FAILED (m_pConn->Open (_bstr_t ("Provider=MSDASQL.1;Persist Security Info=False;User ID=system;Data Source=ArgusDB"),
    

    Mit diesem open funktioniert die Update Funktion nicht:

    if (FAILED (m_pConn->Open (_bstr_t ("Provider=MSDAORA.1;Persist Security Info=False;User ID=system;Password=pw;Data Source=PROD.WORLD"),
    

    DBUpdateNow():

    BOOL CACS400App::DBUpdateNow(CString tabelle, CString feld, CString wert, CString bedingung){
    	_RecordsetPtr pRecordset;
    	try	{
    		_CommandPtr pCommand;
    		HRESULT hr = pCommand.CreateInstance (__uuidof (Command));
    
    		if (FAILED (hr)){
    			AfxMessageBox ("Can't create an instance of Command");
    			return FALSE;		
    		}
    		pCommand->ActiveConnection = m_pConn;
    		CString strQuery="select * from "+tabelle+" where "+bedingung;
    		pCommand->CommandText = (_bstr_t)strQuery;
    
    		hr = pRecordset.CreateInstance (__uuidof (Recordset));
    
    		if (FAILED (hr)){
    			AfxMessageBox ("Can't create an instance of Recordset");
    			return FALSE;		
    		}
    		pRecordset->CursorLocation = adUseClient;
    		pRecordset->Open((IDispatch *) pCommand, vtMissing, adOpenStatic, adLockBatchOptimistic, adCmdUnknown);
    
    		while (!pRecordset->GetadoEOF ()){
    			pRecordset->Fields->GetItem((_variant_t)feld)->Value = (_bstr_t) wert;
    			pRecordset->UpdateBatch(adAffectAll);
    			pRecordset->MoveNext();
    		}
    
    		pRecordset->Close ();
    	} 
    	catch( _com_error &e )	{
    		_bstr_t bstrSource(e.Source());
    		_bstr_t bstrDescription(e.Description());
    		TRACE( "Exception thrown for classes generated by #import" );
    		TRACE( "\tCode = %08lx\n", e.Error());
    		TRACE( "\tCode meaning = %s\n", e.ErrorMessage());
    		TRACE( "\tSource = %s\n", (LPCTSTR) bstrSource);
    		TRACE( "\tDescription = %s\n", (LPCTSTR) bstrDescription);
    
    		AfxMessageBox ((LPCTSTR) bstrDescription);
    
    		return FALSE;		
    	}catch (...){
    		TRACE ( "*** Unhandled Exception ***" );
    		return FALSE;		
    	}
    	return TRUE;		
    }
    


  • Ist die zweite Datenquelle read only?
    Kleiner Trick um einen ordentlichen Connection String zu bekommen:

    Erstell im Explorer eine Datei mit der Endung ".udl"
    Doppelklick drauf, alles wie gewünscht einstellen und dann speichern. Anschliessend öffnest du die Datei mit dem Editor und nimmst den darin fertigformatierten Connection String



  • hmmm also die datenquelle : prod.world wird über ne tsnames.ora deklariert und sieht so aus:

    PROD.WORLD =
    (DESCRIPTION =
    (ADDRESS_LIST =
    (ADDRESS = (PROTOCOL = TCP)(HOST = hostservername.local)(PORT = 1521))
    )
    (CONNECT_DATA = (SID = argus)(SERVER = DEDICATED))
    )

    wenn ich ne udl erzeuge mit der datenquelle ArgusDB kommt der 1. string raus ... aber ich dachte es sei besser das ohne diesen dsn ArgusDB zu machen oder?

    und bitte noch hilfe zu insert und delete benötigt



  • while (!pRecordset->GetadoEOF ()){ 
                pRecordset->Fields->GetItem((_variant_t)feld)->Value = (_bstr_t) wert; 
                pRecordset->UpdateBatch(adAffectAll); 
                pRecordset->MoveNext(); 
            }
    

    Wieso eigentlich UpdateBatch, wenn du alle Datensätze einzeln durchgehst? Nimm mal die normale Update Funktion.

    (edit)
    Wegen dem Connection-String war mein Hintergedanke nur, das deine Datenquelle vielleicht ReadOnly eingestellt war. Hast du das mal geprüft?



  • du sag mal gibt es irgendwo ne beschreibung zu der ado klasse ?
    weil dummerweise bekomm ich keine auto-vervollständigt in mein visual c++
    ich weis leider nicht welche funktionen die klasse eigentlich bietet ... und das updateBatch hab ich auch von der webseite die du mir vor 2 seiten mal gepostet hast ...

    ähm also das open beim insert mach ich direkt auf die connection ...
    also ich create ne instanz und führe dann direkt auf die connection nen exceute aus... also da is gar kein open bei .... also kein direktes ... ich offne nur die verbindung ...

    also was ich meine: bei meinem update offne ich ja ein recordset und dieses öffne ich mit dem modus: pRecordset->Open((IDispatch 😉 pCommand, vtMissing, adOpenStatic, adLockBatchOptimistic, adCmdUnknown);

    und wenn ich das richtig seh ist das ja so das diese zeile die db im "schreibmodus" öffnet ...

    das passiert ja aber beim insert gar nicht ...
    also da führe ich einfach nen execute aus...

    kannst du mir sagen wie ich die verbindung nun anders öffnen soll und da nun den update ausführen kann ???

    (edit)
    ahja wenn ich nur:

    pRecordset->Update();
    

    schreib, passiert gar nix ...

    ich habs jetzt mit

    pRecordset->UpdateBatch(adAffectCurrent);
    

    gemacht das geht auch ...

    aber den insert bekomm ich immer noch nicht hin ... irgendwie stell ich mich zu doof an ... aber so ohne beschreibung is das halt auch etwas schwer...
    also pls ... ich brauch noch 2 funktionen dann geh ich euch net mehr auf den wecker 🙂
    ich muss noch was inserten können und was deleten können mehr brauch ich net ... (erstmal 🙂 ) pls ich brauch quellcode um mir das anzugucken 🙂

    (edit2)
    ok insert geht jetzt doch ...
    hmmm irgendwie seltsam das das gestern net geklappt hat aber ok

    also bleibt noch das delete...
    na ma gucken ob ich das hin bekomm ...

    ne docu zu der ado klasse wäre trotzdem nett also wenn da wer was kennt pls posten ...



  • Die Update() Funktion erfordert wahrscheinlich adLockOptimistic anstatt adLockBatchOptimistic



  • Cpp_Junky schrieb:

    Die Update() Funktion erfordert wahrscheinlich adLockOptimistic anstatt adLockBatchOptimistic

    jo stimmt ... ok thx



  • moin

    so ich hab ma wieder ne frage:

    ich hab ja nun so einiges mit meinen db-funktionen gemacht

    z.b. hab ich für den connect und den delete unterschiedliche funktionen...

    in dem connect öffne ich nur die db-connection und in der delete funktion führe ich nur noch den delete befehl aus ...

    hier entsteht aber ein problem:
    da ich nicht jedes mal nen connect mache muss ich in der delete wissen ob die connection noch besteht...

    also nen isopen befehl oder so ...
    leider geht das ja nur auf recordsets

    also wie bekomm ich raus ob die connection offen ist?

    codes:

    BOOL CACS400App::DBConnectNow(){
    	CoInitialize (NULL);
    
    	// Stablishing a connection to the datasource
    	try	{
    		HRESULT hr = m_pConn.CreateInstance (__uuidof (Connection));
    
    		if (FAILED (hr)){
    			return FALSE;
    		}
    
    		if (FAILED (m_pConn->Open (_bstr_t ("Provider=MSDASQL.1;Persist Security Info=False;User ID=system;Data Source=ArgusDB"),
    					_bstr_t (""), _bstr_t (""), adModeUnknown))){
    			return FALSE;
    		}
    	}catch ( _com_error &e ){
    		_bstr_t bstrSource (e.Source());
    		_bstr_t bstrDescription (e.Description());
    		TRACE ( "Exception thrown for classes generated by #import" );
    		TRACE ( "\tCode = %08lx\n", e.Error ());
    		TRACE ( "\tCode meaning = %s\n", e.ErrorMessage ());
    		TRACE ( "\tSource = %s\n", (LPCTSTR) bstrSource);
    		TRACE ( "\tDescription = %s\n", (LPCTSTR) bstrDescription);
    
    		AfxMessageBox ((LPCTSTR) bstrDescription);
    		return FALSE;
    	}catch (...){
    		TRACE ( "*** Unhandled Exception ***" );
    		return FALSE;
    	}
    	return TRUE;		
    }
    
    BOOL CACS400App::DBDeleteNow(CString aktion){
    	try	{
    
    //ALSO HIER SOLL SO NE ABFRAGE REIN OB m_pConn OFFEN IST
    
    		_bstr_t strSQL=(_bstr_t) aktion;
           //Execute the insert statement
    		m_pConn->Execute(strSQL,NULL,adExecuteNoRecords);
    	} 
    	catch( _com_error &e )	{
    		_bstr_t bstrSource(e.Source());
    		_bstr_t bstrDescription(e.Description());
    		TRACE( "Exception thrown for classes generated by #import" );
    		TRACE( "\tCode = %08lx\n", e.Error());
    		TRACE( "\tCode meaning = %s\n", e.ErrorMessage());
    		TRACE( "\tSource = %s\n", (LPCTSTR) bstrSource);
    		TRACE( "\tDescription = %s\n", (LPCTSTR) bstrDescription);
    
    		CString ausg;
    		ausg.Format("Insert: %s",(LPCTSTR) bstrDescription);
    		AfxMessageBox (ausg);
    
    		return FALSE;		
    	}catch (...){
    		TRACE ( "*** Unhandled Exception ***" );
    		return FALSE;		
    	}
    	return TRUE;		
    }
    

    thx LT


Anmelden zum Antworten