Visual Studio 2008 und CRecordset -.-



  • Hi,

    ich habe so meine Probleme mit besakter Klasse.

    Ich erstelle eine Konsolenanwendung und inkludiere das benötigte:

    #include <afxwin.h>
    #include <afxdb.h>
    #include <iostream>
    #include <conio.h>
    

    Unter Linker optionen stelle ich "static MFC" ein...und mein Code sieht so aus:

    #include "stdafx.h"
    #include "Class_Database.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	Class_Database db;
    
    	db.Open();
    	return 0;
    }
    

    Wo jetzt das Problem ist? Hier:

    http://img261.imageshack.us/img261/4599/odbctr9.jpg

    Hat jemand eine Ahnung voran das liegen könnte, hatte es schonmal geschaft die Verbindung über CDatabase herzustellen, aber bei CRecordset Nutzung kam dasselbe 😕

    Grüsse



  • Achja, die Klasse wird mit dem Assistenten erstellt...die aktuellen MySQL ODBC Treiber sind funktionsfähig!

    Grüsse



  • *Heul*

    Versuche es nun seit 4-5 Stunden lol...

    Ich bin jetzt schon so weit:

    int _tmain(int argc, _TCHAR* argv[])
    {
    	CDatabase dBase;    //KEIN FEHLER
    	dBase.OpenEx(NULL);    //KEIN FEHLER
    
    	if(dBase.IsOpen())    //KEIN FEHLER
    	{
    		Class_Database RecSet(&dBase);    //KEIN FEHLER
    
    		if (RecSet.IsBOF() == true) // ABSTURZ!!!!!
    		{
    
    		}
    	}
    	else
    	{
    		std::cout << "FEHLER!!!!";
    	}
    	return 0;
    }
    

    Ich möchte lediglich 1 Tabelle abfragen -.- Hoffe jemand hat einen Ratschlag für mich, irgendwas muss ich ja falsch machen...

    Grüsse



  • Das ist kein richtiger Absturz sondern ein fehlgeschlagenes ASSERT. Irgendwas passt da nicht (Dieses Assert Makro wird im Debug Modus benutzt um verschiedene Fehlerquellen im Vorfeld abzuprüfen ohne das alles explodiert). Am besten einen Breakpoint auf die Zeile setzen (F9) und in IsBOF() reinspringen und dort mit Einzelschritt weitermachen.



  • Hi,

    danke für die Antwort...habe es eben nochmal probiert, im Releasemodus hat es komischerweise geklappt, ohne Fehler zu erzeugen.

    Im Debugmodus muckt er wieder rum.

    Werde aber nicht so recht aus den Assert schlau 😕

    _AFXDBCORE_INLINE BOOL CRecordset::IsBOF() const
    	{ ASSERT(IsOpen()); return m_bBOF; } //HIER
    
    if (!Check(nRetCode)) // Er springt hier rein und führt den unteren Code aus
    	{
    		// If function sequence error, CRecordset not open
    		CDBException* e = new CDBException(nRetCode);
    		e->BuildErrorString(m_pDatabase, m_hstmt, FALSE);
    		if (e->m_strStateNativeOrigin.Find(_afxOutOfSequence) >= 0)
    		{
    			e->Delete();
    			return FALSE;
    		}
    //...
    

    d.h., wenn ich das richtig verstehe: Es wird eine Excetion geworfen... CRecordset not open :/..... *hilfe*....

    Ich scheine wohl irgendwie was noch nicht ganz begriffen zu haben, was die Klasse angeht 😕 Aber das kopieren von diversen Tutorials führt zu gleichem -.-

    Hoffe jemand hat einen Rat.

    Grüsse 🙂

    P.S. Alternative ODBC Libs die mit VSC 2008 funktionieren sind immer willkommen 🙂



  • Und wozu brauchst Du ODBC?
    Geht mit der API alle viel besser und schneller.



  • Boing! Du hast dein Recordset ja auch gar nicht geöffnet!

    RecSet.Open(AFX_DB_USE_DEFAULT_TYPE, "SELECT * FROM DEINETABELLE");
    while (!RecSet.IsEOF())
    {
        // zeilenweise auslesen
        RecSet.MoveNext();
    }
    


  • Hallo,

    nun das hilft auch nicht:

    int _tmain(int argc, _TCHAR* argv[])
    {
        CDatabase dBase;    //KEIN FEHLER
        dBase.OpenEx(NULL);    //KEIN FEHLER
    
        if(dBase.IsOpen())    //KEIN FEHLER
        {
            Class_Database RecSet(&dBase);    //KEIN FEHLER
    
    		RecSet.Open(AFX_DB_USE_DEFAULT_TYPE, _T("SELECT * FROM events")); //ASSERTION!!!!!!
    		while (!RecSet.IsEOF())
    		{
    			// zeilenweise auslesen
    			RecSet.MoveNext();
    		}
        }
        else
        {
            std::cout << "FEHLER!!!!";
        }
        return 0;
    }
    

    Später sollen alle Daten von einer Oracle Datenbank kommen, leider habe ich keine Oracle Datenbank parat! Möglichkeit wäre, die MySQL und Oracle API in jeweils eine Klasse zu schreiben und das später auszutauschen 😕

    Schnelligkeit ist egal, da ich pro Minute oder so nur ein Statement abschicken möchte. "SELECT * FROM bla WHERE bla" mehr nicht.

    Selbst nach diesem Tutorial klappt es nicht:
    http://www.tutorials.de/forum/c-c/243191-cdatabase-klasse.html

    Ich verzweifel...

    Grüsse und danke nochmal für die Hilfe 🙂

    P.S. Ich habe an der Klasse, die ich mit dem Wizard erstellt habe nichts geändert, selbst der Connectionstring enthält noch ein Passwort!



  • Pack das mal in TRY/CATCH Blöcke und schau ob du ne vernünftige Fehlermeldung bekommst.



  • Hi 🙂

    try
    {
        RecSet.Open(AFX_DB_USE_DEFAULT_TYPE, _T("SELECT * FROM events"));
    }
    catch(CDBException *pE)
    {
        std::cout << "HUHU";
        pE->ReportError();
        pE->Delete();
    }
    

    Ergibt im Release Modus folgende Meldung:

    MFC internal error: unable to load error string from ressource
    

    Im Debug Modus kommt mehrmals eine Assertion -.- Also das Auswahlfenster für die ODBCquelle kommt!

    Ich habe so das Gefühl, dass es etwas mit dem ODBC-Treiber zutun hat 😕
    Weil, wenn ich einfach mal eine andere Quelle auswähle, kommt eine Meldung, dass events nicht gefunden werden konnte o.ä...ist doch shit!

    Grüsse



  • Hast du den Rest auch mal in TRY/CATCH gepackt? Vielleicht gibts vorher schon ne Exception die du übersehen hast. Ich seh da sonst eigentlich nichts problematisches in dem Source. Entweder frisst er den erzwungenen ODBC Dialog nicht:

    dBase.OpenEx(NULL);
    

    oder was auch immer AFX_DB_USE_DEFAULT_TYPE ist, wird von deinem Treiber gar nicht unterstützt. Ersetz das mal durch ForwardOnly.



  • Hallo nochmal, sorry für die Doppelpost etc...

    Ich glaube ich weiß jetzt woran es liegt...

    Statt

    RecSet.Open(AFX_DB_USE_DEFAULT_TYPE, _T("SELECT * FROM events"));
    

    muss man anscheinend bei einer MySQL Datenbank:

    RecSet.Open(CRecordset::snapshot, _T("SELECT * FROM events"));
    

    benutzen.
    CRecordset::dynaset führt ebenfals zu Assertions...hatte irgendwo gelesen, dass dynaset nicht unterstützt wird, kann auch sein, dass es mir gemeldet wurde, als ich ein Beispielprogramm ausprobiert habe...naja, jedenfals scheint es nun ENDLICH zu klappen 🙂

    Ist es eigentlich unratsam die Daten direkt abzufragen?:

    RecSet.m_event_feld1
    

    Oder sollte ich für jedes Feld eine get-Methode einrichten?

    Danke dir vielmals, ohne dich wäre ich nie auf die Idee gekommen, dass es daran liegen könnte 🙂 Gleichzeitig habe ich Exceptions total missachtet!

    Dann kann ich ja jetzt meine Klasse schreiben, fals nochwas sein sollte nerve ich natürlich wieder 😉

    Grüsse



  • HateMFC schrieb:

    ...muss man anscheinend bei einer MySQL Datenbank:

    RecSet.Open(CRecordset::snapshot, _T("SELECT * FROM events"));
    

    benutzen.

    Aaahh, ok dann wars wirklich der Typ des Recordsets.

    CRecordset::dynaset führt ebenfals zu Assertions...hatte irgendwo gelesen, dass dynaset nicht unterstützt wird,

    Dynasets werden von den wenigsten DBs unterstützt. Unter Oracle sollte auch das funktionieren 😉

    Ist es eigentlich unratsam die Daten direkt abzufragen?:

    RecSet.m_event_feld1
    

    Oder sollte ich für jedes Feld eine get-Methode einrichten?

    Wenn die Member public sind, kannst du das machen. Die werden nach jedem Fetch aktualisiert. Sprich: Immer wenn du dich durchs Recordset bewegt hast order aktualisierst (MoveNext/Prev/Top/Bottom/Refresh). Aber wenn du richtig cool bist, baust du dir ne eigene Recordset Klasse die sich dynamisch anhand der Tabellenstruktur organisiert und verwendest dann Funktionen die einfach nur noch Feldnamen zuordnen und den entsprechenden Wert zurückliefern 🙂

    Danke dir vielmals, ohne dich wäre ich nie auf die Idee gekommen, dass es daran liegen könnte 🙂 Gleichzeitig habe ich Exceptions total missachtet!
    ...

    NP 😉



  • Hi 🙂

    Aber wenn du richtig cool bist, baust du dir ne eigene Recordset Klasse die sich dynamisch anhand der Tabellenstruktur organisiert und verwendest dann Funktionen die einfach nur noch Feldnamen zuordnen und den entsprechenden Wert zurückliefern

    Ja bei einem größeren Projekt wäre das sicherlich sinnvoll, bloß ich brauche lediglich ein SELECT-Statement, das war's...es ist immer das selbe. 🙄
    Aber danke für den Tipp 🙂 Lässt sich sicherlich mal einrichten, wenn ich die Handhabung der Klassen besser drauf habe 😉

    Ich habe noch zwei kleine Fragen:

    Ich handhabe die Abfrage, in meiner Klasse, wie folgt:

    //Das Drumherum mit Exceptions etc..habe ich mal weggelassen ;)
    void Klasse::Select(CString s) // "SELECT * FROM" table z.B.
    {
        m_RecSet.Open(CRecordset::snapshot,s);
        //TUE WAS
        m_RecSet.Close();
    }
    

    Ist sowas ok? Habe in der MSDN leider nichts gefunden, bzwgl. einer "query()-Funktion"...Jedenfals scheint es so, als würde er beim 2 Aufruf die Daten der ODBC Quelle gespeichert haben! Sprich, der ODBC Dialog kommt nur 1 mal, was gut ist!

    Ich brauche noch ein DELETE-Statement welches sich, so wie ich das sehe, nicht mit CRecordsets ausführen lässt, sondern nur mit CDatabase.
    z.B.:

    CDatabase cDB;
    cDB.execute("DELETE FROM table");
    

    Klappt wunderbar

    Problem ist, wenn ich beides einbaue, kommt der ODBC Dialog 2. mal 😕 Kann man da irgendwie was gescheites machen? Geht es irgendwie , dass Cdatabase die Verbindung aufbaut und CRecordset diese Daten ebenfals nutzt, ohne den Dialog erscheinen zu lassen?

    Grüsse 🙂



  • Ja, ich glaub du musst nur diesen forceOdbcDialog Parameter setzen:

    DatabaseObjekt.OpenEx(NULL, CDatabase::forceOdbcDialog)
    

    Das erzwingt dann beim Erstellen des Database Objekts den bekannten Dialog, welcher dann die Verbindung herstellt. Danach sollte er nicht mehr erscheinen, vorausgesetzt du übergibst dem Recordset auch immer brav den Pointer aufs Database Objekt:

    CDeineRecordsetKlasse RecSet(&DatabaseObjekt);
    

    btw: Das mit der select-Funktion kannste natürlich machen wie du willst. Meines wissens gibt es nur Open um ein Recordset zu öffnen.



  • Hi 🙂

    Danke, habe eben selbst gemerkt, dass ich den Pointer übergeben muss...das Recordset war auch als Member meiner Klasse eingerichtet, was i.d.F. unsinn ist.
    Jetzt funktioniert es Prima! Danke nochmals 🙂

    Grüsse



  • hooo... nimm ADO ^^ dann bist nicht MFC gebunden, und kannst es in allen c++ frameworks verwenden,,



  • Hi

    Also ich habe mir das nochmal durch den Kopfgehen lassen:

    Aber wenn du richtig cool bist, baust du dir ne eigene Recordset Klasse die sich dynamisch anhand der Tabellenstruktur organisiert und verwendest dann Funktionen die einfach nur noch Feldnamen zuordnen und den entsprechenden Wert zurückliefern 🙂

    Wie würde ich denn da am besten anfangen? Weiß nicht so recht, wie ich an die Tabellenstruktur komme 😕 etc...

    Habe schon überlegt mir mal ADO.NET anzusehen, aber ob das irgendwie hilft.

    Problem ist, dass ich wohl doch dynamische, nicht zur Laufzeit bekannte Tabellen abfragen muss.

    Grüsse 🙂



  • Unter ADO ist das sehr einfach. Du schickst die Abfrage ab und ADO erstellt dir automatisch ein passendes Recordset. Unter ODBC aber muss du vorher den entsprechenden Speicherplatz bereitstellen und an die (kommenden) Felder des Recordsets binden. Das passiert aber, bevor deine Abfrage überhaupt abgeschickt wird. Glaub ich hab das damals so gelöst, das ich erst ein temporäres Recordset mit 255 Feldern erstelle, die Abfrage abschicke und dann "on-the-fly" die Variablen anbinde. Die Informationen über die Felder und Datentypen kriegst du über verschiedene Memberfunktionen (GetODBCFieldInfo oder so AFAIK). Dieses Recordset Gefrickel war übrigens einer der Gründe, weshalb ich dann auf ADO umgestiegen bin 😃



  • Hi 🙂

    Lol ja sehe schon, Recordsets sind so gesehen nur zu gebrauchen, wenn man weiß, was man aus der Datenbank braucht.

    Naja mal schaun, werde gleich mal gucken, wie es sich mit Joins verhält und mal nach einem guten ADO Tutorial ausschau halten. Fals du zufällig ein gutes kennst, wäre ich einem Link nicht abgeneigt 🙂

    Was wäre denn empfehlenswerter ADO oder ADO.NET?

    Grüsse 🙂


Log in to reply