Datenbank(MS-SQL),Werte zurückschreiben
-
Ich habe ein Prog, dass auf eine MS-SQL-Server-Datenbank zugreift. Das lesen, war nicht so das Prob, aber das schreiben. Wie kann ich in meine DB schreiben?
Was ist hier falsch, beziehungsweise, was muss ich in den die Header-Datei schreiben?void CDatenbanktest1Dlg::OnOK() { CDatabase lmsdb; LPCTSTR lpszConnectString = "DSN=lms;UID=lms;PWD=lmsx"; DWORD dwOptions = 0; lmsdb.OpenEx(lpszConnectString, dwOptions ); CRecordset rse( &lmsdb ); rse.Open( CRecordset::dynaset, _T( "SELECT Name FROM nutzer" )); rse.AddNew(); UpdateData(TRUE); rse.Name = m_neuer_benutzername; rse.Update(); CDialog::OnOK(); }
-
Also als alle erste wurde ich das ganze in eine Exception schreiben etwa so :
try
{
if(lmsdb.OpenEx(lpszConnectString, dwOptions )){
CRecordset rse( &lmsdb );rse.Open( CRecordset::dynaset, _T( "SELECT Name FROM nutzer" ));
rse.AddNew();
rse.Name = m_neuer_benutzername;lmsdb..Close();
}
cout<<"Die Daten sind erforgleich in DB geladen"<<endl;
}
catch(CDBException* pe)
{
cout<<"Fehler beim laden von Restdaten:"<<pe<<endl;
pe->Delete();
}
oder soger AddNew noch getrennter in CDBException reinklatschen aber warum benutz du nicht INSERT ??
-
Ja, mit dem try und catch is schon ni schlecht, aber mein Problem is, dass ich mit dem ".Operator" nicht auf die Elemente der Datenbank zugreifen kann um sie dort zu ändern. Er bringt nämlich folgende Fehlermeldung:
Z:\datenbanktest1\datenbanktest1Dlg.cpp(220) : error C2039: 'Name' : Ist kein Element von 'CRecordset'
c:\programme\microsoft visual studio\vc98\mfc\include\afxdb.h(564) : Siehe Deklaration von 'CRecordset'Bedeutet das, dass ich diese Elemente noch irgendwie deklarieren muss?
-
Hallo !
Kann es sein, dass du das "m_" vergessen hast: rse.**m_**Name ?
Übrigens sollte man das, was man auf macht, auch wieder zu machen (rse.Close()).
Tschüss
-
Ja, weis ich, hab nur vergessen das Close() noch mit hinzuschreiben.
Aber wegen dem .m_Name bin ich mir nicht sicher, weil ich denke, dass sich .Name auf die Spalte der Datenbank bezieht und nicht auf die Membervariable m_Name. Aber wie gesagt, ich bin mir da nicht sicher, da ich das erste mal mit Datenbanken unter MFC arbeite. Ich denke die Fehlermeldung hängt damit zusammen, dass man diese Spaltennamen ersteinmal deklarieren muss und zwar so hier ungefähr:void CDatenbanktest1Dlg::DoFieldExchange(CFieldExchange* pFX) { pFX->SetFieldType(CFieldExchange::outputColumn); RFX_Int(pFX, _T("[id]"), m_id); RFX_Text(pFX, _T("[Name]"), m_neuer_benutzername); RFX_Text(pFX, _T("[Kennwort]"), m_passwort); RFX_Bool(pFX, _T("[Enable]"), m_enable); }
Und dann muss man diese Variablen noch instanzieren. Ungefähr so:
CDatenbanktest1Dlg::CDataODBCSet(CDatabase* lmsdb) : CRecordset(lmsdb) { m_id = 4; m_neuer_benutzername = _T(""); m_passwort = _T(""); m_enable = 1; }
Aber so ganz stimmt das ebend auch noch nicht, sonst hätte ich schon einen Freudenschrei ausgerufen....
-
Wie wäre es, diese Arbeit dem Assistenten zu überlassen ?
- mit der rechten Maustaste in dem Arbeitsbereich (Klassenansicht) auf das Projekt klicken
- "Neue Klasse" auswählen -> ein neuer Dialog erscheint:
- Klassentyp: "MFC-Klasse" (so lassen)
- Name: einen sinnvollen ausdenken (z.B. "TestTabelle" (naja, nicht gerade sinnvoll))
- Basisklasse: CRecordset
- "OK" anklicken -> noch ein neuer Dialog erscheint:
- einen (vorher eingerichteten) ODBC-Treiber auswählen (dein Quelltext sieht nach ODBC aus...)
- "Snapshot" oder "Dynaset" auswählen
- "OK" anklicken -> noch ein neuer Dialog erscheint:
- evtl. ein Datenbank-Passwort angeben -> es erscheint eine Übersichz über alle Tabellen in der DB
- eine Tabelle auswählen (werden mehrere Tabellen markiert, entsteht ein Kreuzprodukt)
- "OK" anklicken
-> dem Projekt wird eine neue Klasse (von CRecordset abgeleitet) hinzugefügt. Die enthält schon alle Membervariablen entsprechend den Feldern der Datenbank (mit "m_" vorneweg und meistens sind die Datentypen richtigIn der Header-Datei dieser neuen Klasse muss
#include <afxdb.h>
eingefügt werden.
Dann die Header-Datei der neuen Klasse im Programm einbinden:
#include "TestTabelle.h"
und (z.B. in OnOK()) ein Objekt davon erstellen:
CTestTabelle Test;
und jetzt sollte dir die Autovervollständigung auch die Member und Methoden anzeigen, nachdem du
Test.
geschrieben hast.
[edit]
Moment mal,... *denk*
Wie hast du denn die Daten aus der Datenbank gelesen, wenn du noch keine von CRecordset abgeleitete Klasse hattest ? Oder bin ich jetzt auf dem Holzweg ?
[/edit][ Dieser Beitrag wurde am 12.11.2002 um 15:41 Uhr von isabeau editiert. ]
-
So hier in der "::OnInit()"-Funktion:
CDatabase lmsdb; // lmsdb.OpenEx( NULL, CDatabase::forceOdbcDialog ); LPCTSTR lpszConnectString = "DSN=lms;UID=lms;PWD=lmsx"; DWORD dwOptions = 0; lmsdb.OpenEx(lpszConnectString, dwOptions ); CRecordset rs( &lmsdb ); rs.Open( CRecordset::dynaset, _T( "SELECT Name FROM Nutzer" ) ); CString wert; int n = rs.GetODBCFieldCount( ); while( !rs.IsEOF() ) { for( int i = 0; i < n; i++ ) { rs.GetFieldValue( i, wert ); m_benutzername.AddString(wert); } rs.MoveNext( ); } rs.Close( ); lmsdb.Close( );
Ich hab jetzt außerdem das Zurückschreiben mit dem Klassenassistenten erstellt. Und das funzt auch, bis auf das Werte zuweisen. Hab das so hier geschrieben:
void CDatenbanktest1Dlg::OnOK() { CDataODBCSet lmsdb; LPCTSTR lpszConnectString = "DSN=lms;UID=lms;PWD=lmsx"; DWORD dwOptions = 0; lmsdb.Open( CRecordset::dynaset, _T( "INSERT INTO nutzer VALUES(id,Name,Kennwort,enable)" )); lmsdb.AddNew(); lmsdb.m_id=m_id_; lmsdb.m_Name=m_neuer_benutzername; lmsdb.m_Kennwort=m_passwort; lmsdb.m_Enable=m_enable_; lmsdb.Close(); }
Aber der kennt ja gar keinen "=Operator". Wie kann ich jetzt die Werte aus dem EDIT-Feld in die Feld-Variablen schreiben?
-
Mmmmhhhh, CDataODBCSet kenne ich gar nicht und habe ich auch nicht in der MSDN gefunden...
Ansonsten sieht es im Moment so aus, als wenn du zwei Verfahren mischt, und zwar 1) Datenaustausch über die Membervariablen der von CRecordset abgeleiteten Klasse und 2) Datenaustausch über SQL-Statements.Ich kann es jetzt nicht ausprobieren, aber vielleicht helfen ja ein paar Gedanken:
Könnte so klappen:zu 1)
- den Anfang in OnOK() so lassen, aber bei lmsdb.Open(...) keine SQL-Anweisung mitschicken (evtl. NULL als zweiten Parameter übergeben)
- UpdateData(TRUE); // liest die Inhalte der Editfelder in die zugehörigen Membervariablen (z.B. in m_neuer_benutzername) ein
- lmsdb.AddNew(); // erstellt einen neuen leeren Datensatz
- lmsdb.m_Name=m_neuer_benutzername; // Inhalte der Editfeld-Member an Recordset-Member übergeben (die anderen analog)
- lmsdb.Update(); // Datensatz aktualisieren
- lmsdb.Close(); // Datenbank schliessenzu 2)
- UpdateData(TRUE); // liest die Inhalte der Editfelder in die zugehörigen Membervariablen (z.B. in m_neuer_benutzername) ein
- CString cSQL; // Variable für SQL-Anweisung erstellen
- Editfeld-Member in die SQL-Anweisung einbauen:cSQL = "INSERT INTO nutzer VALUES(" cSQL += m_id; // ich gehe mal davon aus, dass das ein Zahlenwert ist, dann ohne Apostroph vor und hinter m_id cSQL += ",'"; // Komma und Apostroph einbauen cSQL += m_neuer_benutzername; // ich gehe mal davon aus, dass das ein String ist, dann mit Apostroph vor und hinter m_neuer_benutzername cSQL += "','"; // Apostroph und Komma und Apostroph einbauen cSQL += m_passwort; // wie m_neuer_benutzername cSQL += "','"; // Apostroph und Komma und Apostroph einbauen cSQL += m_enable_; // falls das ein boolscher Wert ist, weiss ich nicht genau ob mit oder ohne Apostroph -> mal ausprobieren cSQL += "')"; // Apostroph (oder vielleicht auch kein Apostroph) und Klammer einbauen
- lmsdb.Open( CRecordset::dynaset, _T(cSQL)); // Datenbank mit der erstellten SQL-Anweisung öffnen
Eigentlich ist der neue Datensatz jetzt schon in der Datenbank drin und man kann sie gleich wieder zu machen. Ob das aber wirklich funktioniert, weiss ich nicht. Schliesslich wurde kein AddNew() aufgerufen...Fällt mir gerade noch ein:
In der Klasse CDatabase gibt es die Methode ExecuteSQL(LPCSTR lpszSQL). Damit kannst du auch SQL-Anweisungen (an eine geöffnete) Datenbank abschicken.
-
Ja, danke dir für deine Anregungen, habs aber schon hingekriegt.*juhu*
Und zwar so: (vielleicht kannst du es ja auch mal gebrauchen
)
void CDatenbanktest1Dlg::OnOK() { CDataODBCSet lmsdb; try { if(lmsdb.Open( CRecordset::dynaset, _T( "SELECT * FROM Nutzer" ) )) { UpdateData(TRUE); lmsdb.AddNew(); lmsdb.m_id = m_id; lmsdb.m_Name = m_neuer_benutzername; lmsdb.m_Kennwort = m_passwort; lmsdb.m_Enable = m_enable; lmsdb.Update(); lmsdb.Close(); } MessageBox("Die Daten sind erforgleich in DB geladen"); } catch(CDBException* pe) { AfxMessageBox("Fehler beim laden von Restdaten!"); pe->Delete(); } }
Dabei ist darauf zu achten, dass die Membervariablen der Steuerelemete(z.B. Editbox)nicht vom Typ "Control" sind, sondern vom Typ "Wert", da sonst der "=Operator" bei der Wertzuweisung nicht mitmacht.
Die Klasse "CDataODBCSet" stammt aus meiner Feder und wurde mit dem Klassenassistenten erstellt, so, wie du mir geraten hast.
Danke nochmal für deine Hilfe...