MySQL Syntax in C++ (MFC)
-
danke für den link und den code, das hatte ich vor kurzem auch entdeckt. ausserdem habe ich erfahren, dass es grundsätzlich zwei möglichkeiten gibt mit DB zu kommunitieren. nämlich mittels CRecordset und CDatabase oder mittels "mysql++.h".
link behandelt die erste möglichkeit (man benutz sie für vc++ 6.0)
code benutz die möglichkeit CRecordset und CDatabase wie im link beschreiben.
habe folgendes gemacht:-CDBSet von CRecordset abgeleitet, felder bekann gemacht in AFX-FIELD INIT und FIELD MAP...
- in DB schreiben:
CDatabase db; CDBSet rs( &db); //DB öffnen CString ODBC;ODBC = "DRIVER={MySQL ODBC 3.51 Driver};PORT=3306;SERVER=xxx;DATABASE=pruefmittel;USER=p;PWD=pm;OPTION=2048"; db.OpenEx(_T(ODBC),db.noOdbcDialog); if (!db.IsOpen())//falls öffnen fehlgeschlagen { AfxMessageBox("Fehler beim Verbinden mit Datenbank"); } else { rs.AddNew(); rs.m_SerNr = sSerNr; rs.m_PersNr2 = Pnr; rs.m_Vorname2 = Vorname; rs.m_Name2 = Name; rs.m_Datum3 = datum; rs.m_Uhrzeit3 = curtime; rs.Update();
}
ich kann es kompilieren.
beim ausführen bekomme ich eine meldung: "Datensatzgruppe kann nur gelesen werden"meine frage: ist die fehlermeldung ein problem mit c++ oder datenbank
und öffne ich die DB richtig?
-
Ugene schrieb:
beim ausführen bekomme ich eine meldung: "Datensatzgruppe kann nur gelesen werden"
meine frage: ist die fehlermeldung ein problem mit c++ oder datenbank
und öffne ich die DB richtig?Das liegt am OpenEx, wenn du danach mal suchst findest du einen Thread über mehrere Seiten, wo ich das Problem hatte.
Nimm entweder das Open von CDatabase oder das von CRecordset direkt.
Aber OpenEx geht zumindest mit VC6 nicht.
-
danke, es lag tatsächlich an OpenEx.
nun habe ich aber ein ASSER in dbcore.cpp line 275
dort heißt es:// Exclusive access not supported. ASSERT(!(dwOptions & openExclusive));
hat jemand ein tipp?
-
Was macht das da:
OPTION=2048
-
estartu schrieb:
Was macht das da:
OPTION=2048daran liegts wahrscheinlich nich. hab es ganz weggelassen und gleiche ASSERT kommt trotzdem.
hab folgendes gefunden: http://support.microsoft.com/?kbid=839782
-
Hats denn geholfen? Du hast doch gar kein Access?
-
ich kann es leider nicht machen.
ehrlich gesagt, denke ich dass der fehler im code ist. irgendwo in View oder Doc oder sonstigen classe.
ich bin schon soweit, dass ich mein backup lade und die ganze datenbank anbiendung von vorne anfange.daher würde ich dich estartu bieten mir eine kleine einführung zu posten. schritt für schritt. wo was ableiten, massegemaps ect.
dieser link
http://www.se.fh-heilbronn.de/usefulstuff/VCPLUS6/kap14.htmist zwar gut, aber er behandelt ein projekt das zu sehr an die automatik von MFC gebunden ist. ich dagegen muss alles per hand machen, weil ich ein existierendes projekt an die datenbank anbinden muss. bisher habe ich auf textfiles geschrieben.
falls es doch zu aufwendig wird, möchte ich mich an dieser stelle für deine hilfe 1000 mal bedanken.
-
Naja, du kannst auch so den Assistenten nutzen, keine Angst.
Mach mal in der Klassenansicht rechte Maustaste auf dein Projekt, dann wähle "neue Klasse", dann MFC-Klasse und dann als Basisklasse CRecordset.
Dann solltest dir schon einiges bekannt vorkommen.Das war jetzt aus dem Kopf geschrieben. Solltest du es nicht finden, suche ich es nochmal raus.
(An einer Einführung arbeite ich fürs Magazin, komme aber nicht so oft dazu.
)
-
hey danke,
ich habs gleich ausprobiert, und ich kann tatsächlich den assistenten benutzen. man war ich blöd und hab alles per hand eingefügt, daher hats auch nicht funktioniert.ich starte nun mein backup und mache alles neu. melde mich dann ob es geklappt hat.
danke nochmal
-
Ugene schrieb:
man war ich blöd und hab alles per hand eingefügt, daher hats auch nicht funktioniert.
Blöd ist der falsche Ausdruck.
Eher ist es recht kompliziert, die Zusammenhänge zu erkennen - besonders, wenn man gerade mit dem Thema anfängt.Später ist es jedenfalls ohne grosse Probleme möglich, mal ein Feld von Hand nachzupflegen oder zu löschen.
-
so, nun habe ich folgendes nach dem backup laden gemacht:
1. eine neue klasse erstellt, abgeleitet von CRecordset, CRecordView und CDocument brauche ich nicht, da ich die daten nicht im fenster darstellen will.
2. msdn bzgl. CRecordset durchgelesennun mein code:
CDatabase db; CString ODBC; CDatenBankSet rs; long datum = 0; long zeit = 0; ODBC = "DRIVER={MySQL ODBC 3.51 Driver};PORT=3306;SERVER=172.17.108.16;DATABASE=pruefmittel;USER=pm;PWD=pm25lh08"; //DB öffnen db.OpenEx(_T(ODBC),db.noOdbcDialog); if (!db.IsOpen())//falls öffnen fehlgeschlagen { AfxMessageBox("Fehler beim Verbinden mit Datenbank"); } else { rs.AddNew( ); rs.m_SerNr = sSerNr; rs.m_PersNr2 = Pnr; rs.m_Vorname2 = Vorname; rs.m_Name2 = Name; rs.m_Datum3 = datum; rs.m_Uhrzeit3 = zeit; if( !rs.Update( ) ) { AfxMessageBox( "Record not added; no field values were set." ); } } db.Close();
kompiliert, kein fehler, keine warnung.
beim ausführen folgender assert bei AddNew();
ASSERT(m_hstmt != SQL_NULL_HSTMT); // we can't construct an INSERT statement w/o any columns
ich verstehe nicht warum ich so große problemme habe. eigentlich ist es nichts besonderes. verbinden->auslesen->schließen.
wie macht ihr das?
-
Hmm, klingt als hättest du die Tabelle nicht sauber eingebunden.
Mir fehlt da auf jeden Fall ein
rs.Open();
sonst wird das Insert bald die nächste Meldung für dich haben.
Versuchen wirs mal anders: Was steht in GetDefaultSQL und GetDefaultConnect vom Recordset?
Was im DoFieldExchange?Hast du eigentlich die ODBC Datenquelle erstellt? Mich wundert dieser kryptische String für das OpenEx.
-
in der vom CRecordset abgeleiteten klasse steht das drin:
///////////////////////////////////////////////////////////////////////////// // CDatenBankSet IMPLEMENT_DYNAMIC(CDatenBankSet, CRecordset) CDatenBankSet::CDatenBankSet(CDatabase* pdb) : CRecordset(pdb) { //{{AFX_FIELD_INIT(CDatenBankSet) m_SerNr = _T(""); m_PersNr2 = _T(""); m_Vorname2 = _T(""); m_Name2 = _T(""); m_nFields = 6; //}}AFX_FIELD_INIT m_nDefaultType = dynaset; } CString CDatenBankSet::GetDefaultConnect() { return _T("ODBC;DSN=pruefmittel"); } CString CDatenBankSet::GetDefaultSQL() { return _T("[personen]"); } void CDatenBankSet::DoFieldExchange(CFieldExchange* pFX) { //{{AFX_FIELD_MAP(CDatenBankSet) pFX->SetFieldType(CFieldExchange::outputColumn); RFX_Text(pFX, _T("[SerNr]"), m_SerNr); RFX_Text(pFX, _T("[personen].[PersNr]"), m_PersNr2); RFX_Text(pFX, _T("[personen].[Vorname]"), m_Vorname2); RFX_Text(pFX, _T("[personen].[Name]"), m_Name2); RFX_Date(pFX, _T("[personen].[Datum]"), m_Datum3); RFX_Date(pFX, _T("[personen].[Uhrzeit]"), m_Uhrzeit3); //}}AFX_FIELD_MAP } ////////////////////////////////////////////////////////////////////////////
-
also nun habe ich das halbe internet durchgesucht. und meiner verständnis nach habe ich keinen gravierenden fehler gemacht.
die datenbankprogrammierung (mySQL) mittels MFC VC++ 6.0 verstehe ich von der theorie so:
1. erzeuge ich die datenbank, ich nenne sie "pruefmittel".
2. in der datenbank lege ich eine tabelle fest, diese nenne ich personen. sie beinhaltet 6 spalten (sSerNr, PersNr, Vorname, Name, Datum, Uhrzeit).
3. ich erzeuge im datenquellen-administrator (Systemsteuerung->Verwaltung->Datenquellen) die ODBC datenquelle.
4. im meinem existierenden projekt füge ich mit dem assistenen neue klasse hinzu. diese Klasse ist abgeleitet von CRecordset. und mache die angelegte datenquelle dieser klasse bekannt.(alles mittels assistent).
5.ich stelle verbindung zu der datenquelle aus einer bieliebigen methode (z.B CPersonenDgl)CDatabase db; CString ODBC; CDatenBankSet rs; long datum = 0; long zeit = 0; ODBC = "DRIVER={MySQL ODBC 3.51 Driver};PORT=3306;SERVER=172.17.108.16;DATABASE=pruefmittel;USER=pm;PWD=pm25lh08"; //DB öffnen db.OpenEx(_T(ODBC),db.noOdbcDialog);
6. nun übergebe ich meine variablen an die datenbank-variablen und speichere den inhalt mittel update()
rs.AddNew( ); rs.m_SerNr = sSerNr; rs.m_PersNr2 = Pnr; rs.m_Vorname2 = Vorname; rs.m_Name2 = Name; rs.m_Datum3 = datum; rs.m_Uhrzeit3 = zeit; rs.Update( )
theoretisch müssen die daten ab hier in der db liegen.
meine frage an euch wäre:
ist mein gedankengang richtig? oder sieht jemand lücken, fehler, o.ä.
-
hier ist die lösung verboregen. mal schauen wie weit ich damit komme
-
So grundlegend ist es richtig, nur dass du es mal so versuchen solltest:
rs.Open(); rs.AddNew( ); rs.m_SerNr = sSerNr; rs.m_PersNr2 = Pnr; rs.m_Vorname2 = Vorname; rs.m_Name2 = Name; rs.m_Datum3 = datum; rs.m_Uhrzeit3 = zeit; rs.Update( )
Oder so:
CDatabase db; CString ODBC; long datum = 0; long zeit = 0; ODBC = "DRIVER={MySQL ODBC 3.51 Driver};PORT=3306;SERVER=172.17.108.16;DATABASE=pruefmittel;USER=pm;PWD=pm25lh08"; //DB öffnen db.OpenEx(_T(ODBC),db.noOdbcDialog); CDatenBankSet rs(db); rs.AddNew( ); rs.m_SerNr = sSerNr; rs.m_PersNr2 = Pnr; rs.m_Vorname2 = Vorname; rs.m_Name2 = Name; rs.m_Datum3 = datum; rs.m_Uhrzeit3 = zeit; rs.Update( )
So, wie du es bieher hast, existiert keine Verbindung zwischen dem Datenbankobjekt und dem Recordset.
Zumindest das obere funktioniert eigentlich immer bei vom Assistenten erzeugten Klassen.
-
ich habe nun folgendes ausprobiert:
db.OpenEx( NULL, CDatabase::forceOdbcDialog );
programm gestartet und dann verbindung zur datenbank "per hand" mittels ODBC-fenster hergestellt.
ich bekomme ein ASSERT in dbcore.cpp line 1580, habe ich shon vorher erwähnt:
ASSERT(m_hstmt != SQL_NULL_HSTMT);
// we can't construct an INSERT statement w/o any columnsich stelle fest: 1. es liegt nicht an OpenEx();
2. Bug ist in der Tabelle: "man könne keinen Insert statement ohne spalten konstruieren"hier: http://db.apache.org/derby/docs/10.1/ref/rrefsqlj40774.html steht folgendens:
An INSERT statement creates a row or rows and stores them in the named table. The number of values assigned in an INSERT statement must be the same as the number of specified or implied columns.
folge: mein programm ist nicht in der lage spalten/reihen zu erzeigen
ich stelle fest: 3. bug ist in INSERT
-
Es ist komisch, das AddNew ist es also.
Mach bitte vor der Zeile mit AddNew mal:
ASSERT(rs.IsOpen());
und sag, ob der anschlägt.
Hast du meine Vorschläge mal probiert? Dein Code von eben war ja wieder was anderes.
-
hi estartu,
ja ich habe rs.Open(); eingefügt und ASSERT(rs.Open()) danach, um zu sehen ob rs öffnen konnte.rs.Open(); //...verbindung ASSERT(rs.IsOpen()); rs.AddNew( ); rs.m_SerNr = sSerNr; rs.m_PersNr = Pnr; rs.m_Vorname = Vorname; rs.m_Name = Name; rs.m_Datum = datum; rs.m_Uhrzeit = zeit;
nun taucht ein ASSERT von timecore.cpp line 32,
ASSERT(nDay >= 1 && nDay <= 31);
da stimmt was mit dem datumformat nicht. mal sehen was ich da finde.
-
oh man, hab falsch abgetippt, verbindung ist natürlich ganz oben.
sorry