Mit CRecordset in Datenbank schreiben



  • Hallo!

    Ich habe schon im Forum gesucht, aber noch keine Antwort gefunden, mit der ich 100%ig weiterkomme.

    Mein Problem ist, dass ich eine Accesdatenbank aus meiner Anwendung mit Hilfe von CDatabase und CRecordset ansprechen kann, und auch Daten herauslesen kann, aber keine Ahnung habe, wie ich etwas hineinschreibe.

    Hier im Forum habe ich immer solche Tips gefunden, dass man eine eigene Klasse von CRecordset ableiten muss, und dann mit den Methoden AddNew() und Update() Einträge in die Datenbank schreiben kann. Aber irgendwie muss man doch erst mal sagen können, welche Spalte der Datenbank welchen Wert bekommen soll.

    In den Beispielen wurde dann immer gesagt, ich muss in meiner abgeleiteten CRecordset Klasse Membervariablen anlegen, die dann die Spalten repräsentieren. Aber das kann doch gar nicht hinhauen, weil doch der Bezug zur Datenbank fehlt.

    Kann mir wer helfen ???

    Gruß Maik



  • Welches VC hast du? 6 oder 2003? 🙂

    Die Anleitungen sind so schon korrekt. Das funktioniert auch. 😉
    Den Bezug zur Datenbank stellt eine Funktion her: DoFieldExchange. Die legt fest, welches Feld zu welcher Variablen gehört und was das für Daten sind.

    Wenn du VC6 hast, leg einfach mal eine neue Klasse mit Basisklasse CRecordset an und wähle eine Tabelle aus. Dann siehst du, was ich meine.
    Wie das bei 2003 geht weiß ich leider nicht. 😞
    Ich könnte dir aber eine Klasse vom VC6 als "Schablone" schicken. Da kannst du dann abgucken, wie das geht. 🙂



  • Oder schaust mal hier



  • strSQL = "SELECT * FROM Tabellenname WHERE ID = " + strID + ";";  
    
      try
      {
        pDBDatenbank->Open(CRecordset::snapshot, strSQL);
        pDBDatenbank->Edit();
        pDBDatenbank->m_Bemerkungen = m_Bemerkungen;
        pDBDatenbank->m_Datenbank = m_Datenbank;
        pDBDatenbank->m_Datenbanktyp = m_Datenbanktyp;
        pDBDatenbank->m_Version = m_Version;
        pDBDatenbank->m_Zugriffsname = m_Zugriffsname;
        pDBDatenbank->m_Rechner_ID = GetRechnerID();
    
        pDBDatenbank->Update();
        pDBDatenbank->Close();
      }
      catch(CDBException* pe)
      {
        AfxMessageBox(pe->m_strError);
      }
    

    Esco



  • Also, ich habe VC 2003.
    Ich habe mir mal diesen Artikel hier reingezogen http://msdn.microsoft.com/library/deu/default.asp?url=/library/DEU/vccore/html/_core_recordset.3a_.architecture_.28.odbc.29.asp, und da steht irgendwie drin, dass man nur die Feldatenmember eingeben muss, und um den Rest kümmert sich dann das Framework.

    Naja, nichts desto trotz habe ich es auch mal mit DoFieldEchnage ausprobiert, aber da bekomme ich immer den Fehler "Datensatzgruppe kann nur gelesen werde", wenn ich AddNew() aufrufe. Und das, obwohl icg das Flag "CRecordset::append" und einige andere bei Open() schon benutzt habe.

    Ich kann euch leider keinen Code schicken, da der Entwicklungsrechner nicht am Netz ist . . .



  • Mach mal Open ohne irgendwas. (Hab da nie Parameter.)
    Die Tabelle ist auch nicht gesperrt oder so?



  • Also, hab jetzt mal Open() ohne irgendwas gemacht. Da kommt er dann mit "Syntaxfehler in FROM-Klausel". Sehr mysteriös . . .

    Wenn ich im zweiten Paramter "SELECT * FROM Messwerte" übergebe, dann kann ich aus der Tabelle lesen, aber nicht reinschreiben, weil dann der Fehler aus meinem letzten Post kommt.

    Hmmmmm . . . .

    Das die Tabelle gesperrt ist, glaube ich nicht, kann ich aber auch nicht mit Gewissheit sagen. Wo steht das denn in ACCESS? Schreibgeschützt ist sie auf alle Fälle nicht.



  • Ich glaube was Estartu meint ist gesperrt durch andere Anwendung sprich ob die DB schon geöffnet ist und deshalb nur Read only



  • Mach Access zu bevor du testest. 🙄
    Access kann nur einen Zugriff gleichzeitig.



  • so, jetzt bin ich zu hause, und kann mal etwas Code posten. leider klappte es nämlich auch mit geschlossenem ACCESS nicht. . .

    Hier ist meine Klasse:

    class CRSet : public CRecordset
    {
    public:
    	long feld1;
    	double feld2;
    	CString feld3;
    	CString feld4;
    
    	//CRSet(void);
    	CRSet(CDatabase* pDatabase = NULL):CRecordset(pDatabase)
    	{
    		m_nFields = 4;
    		m_nParams = 0;
    		feld1 = 3;
    		feld2 = 0.0;
    		feld3 = "test";
    		feld4 = "test1";
    	}
    
    	virtual void DoFieldExchange(CFieldExchange *pFX)
    	{
    		pFX->SetFieldType(CFieldExchange::outputColumn);
    		RFX_Long(pFX, _T("[Messpunkt]"), feld1);
    		RFX_Double(pFX, _T("[Messwert]"), feld2);
    		RFX_Text(pFX, _T("[Datum]"), feld3);
    		RFX_Text(pFX, _T("[Zeit]"), feld4);
    	}
    	DECLARE_DYNAMIC(CRSet)
    
    	~CRSet(void);
    };
    

    Und hier ist der Code, wo das herauslesen funktioniert, aber er mir schon beim aufrufen der Funktion CanUpdate() andeutet, dass es nicht funktionieren wird, was es dann ja auch nicht tut.

    // Instanz von CRSet erstellen.
    	// Dem Konstruktor als Parameter die Instanz von CDatabase
    	// mitgeben.
    	CRSet rset(&dbmw);
    
    	rset.Open(CRecordset::snapshot, _T("SELECT * FROM Messwerte"));
    	rset.GetFieldValue(1, variant);
    	dblStr.Format("%f", variant.m_dblVal);
    	MessageBox(dblStr,NULL,MB_OK);
    
    	//
    	rset.MoveNext();
    	rset.GetFieldValue(1, variant);
    	dblStr.Format("%f", variant.m_dblVal);
    	MessageBox(dblStr,NULL,MB_OK);
    
    	if(!rset.CanUpdate())
    		MessageBox("Recordset kann nicht bearbeitet werden !", NULL, MB_OK);
    
    	// neuen Datensatz hinzufügen
    	rset.MoveLast();
        rset.AddNew();
    	rset.feld1 = 3;
    	rset.feld2 = 213.43;
    	rset.feld3 = "test";
    	rset.feld4 = "Test1";
    	rset.Update();
    

    Fällt euch jetzt vielleicht etwas direkt auf, was falsch sein könnte. Dass ich keinen Pointer auf meine CRSet Klasse erstellt habe, und dann über diesen die Methoden aufrufe ist doch wohl egal, oder nicht? Ich meine das Lesen aus der Datenbank funktioniert ja auch.



  • probiers mal mit CRecordset::dynaset anstelle von deinem Snapshot!



  • Okay, mit dynaset gibt es keine Fehlermeldungen mehr (was ich schon mal nicht verstehe), aber die Daten werden trotzdem nicht in die Tabelle eingetragen. . .



  • Ich habe es auf diese Art noch nicht gemacht, aber irgendwie bin ich skeptisch, dass der beim Schreiben noch weiß, auf welcher Tabelle er arbeiten soll.

    Ich poste dir Morgen mal wie das beim VC6 aussieht. Vielleicht geht es ja so. 🙂



  • Soo, ich habe jetzt noch etwas rumprobiert, und herausgefunden, dass für mein Programm scheinbar alles in Ordnung ist.

    Ich habe nämlich mal MoveLast() gemacht, und dann Delete().
    Dann habe ich versucht über GetFieldValue() einen Wert zu holen. Da hat er natürlich gemeckert, weil er nicht auf einen gültigen Eintrag zeigt, was ja auch so richtig ist, da ich ihn ja gerade gelöscht habe.
    Mache ich jetzt wieder MoveLast() und GetFieldValue(), dann holt er mir auch wirklich einen Wert aus dem Datensatzt, der sich vor dem befand, den ich gelöscht habe.
    Das heisst dann ja wohl, dass der Datensatz wirklich gelöscht wurde. Das Problem ist nur, dass man davon in der ACCESS-Tabelle nichts sieht, egal, ob ACCESS nun gleichzeitig auf, oder geschlossen, war.

    Es scheint also die Frage zu sein, warum wird die Tabelle in ACCESS nicht aktualisiert, obwohl ich natürlich auch Update() aufrufe (siehe Quellcode).



  • hääte noch ne kleine Idee:
    probier mal vornweg:

    // Sicherstellen, daß alle Änderungen am aktuellen
    // Datensatz gespeichert wurden.
    if (CanUpdate() && !IsDeleted())
    {
    Edit();
    if (!UpdateData())
    return;
    Update();
    }
    


  • Hi!

    Also das funktioniert auch nicht. Ich bin ja echt am Verzweifeln. Habt ihr denn irgend etwas verdächtiges in meinem Quellcode gefunden? Und vor allem, warum kann ich ohne Probleme aus der datenbank lesen, aber nichts reinschreiben ????



  • Für die,die es interessiert:

    Ich habe eine Instanz von CDatabase erstellt, und diese dann dem CRecordset Konstruktor übergeben. Vorher habe ich allerdings noch die CDatabase::BeginTrans() Methode aufgerufen, um Transaktionen zwischen meinem Programm und der datenbank überhaupt erst möglich zu machen. Wenn ich dann einen neuen Recordset mit AddNew() und Update() eingefügt habe, muss ich noch CDatabase::CommitTrans() aufrufen, um die Transaktion abzuschließen.

    Das wars . . .
    Gruß
    Maik



  • ah in diesem Sinne klappt es nun?

    Freut mich für dich



  • ja, jetzt ist alles in Butter 😃 😃 😃


Anmelden zum Antworten