vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 2

Tag 14

Daten aus ODBC- Datenbanken abrufen

Eine große Zahl von Anwendungen greift auf Datenbanken zu. Angefangen beim persönlichen Organizer bis hin zu großen Personalsystemen in Unternehmen speichern und verwalten Datenbanken alle Datensätze, die eine Anwendung verwendet und manipuliert. Visual C++ bietet vier verschiedene Technologien für die Verwendung und den Zugriff auf Datenbanken in Ihren Anwendungen: Data Access Objects (DAO), ODBC, OLE DB und ActiveX Data Objects (ADO). In der heutigen und morgigen Lektion gehen wir auf zwei dieser Technologien näher ein und befassen uns mit den Unterschieden sowie dem Einsatz in eigenen Anwendungen.

Heute lernen Sie, wie ...

Datenbankzugriff und ODBC

Die meisten Anwendungen im geschäftlichen Bereich arbeiten mit Daten. Diese Anwendungen verwalten und manipulieren Datensätze, die in Datenbanken gespeichert sind. Wenn Sie eine geschäftliche Anwendung erstellen, kommen Sie um den Zugriff auf eine Datenbank nicht herum. Die Frage ist, welche Datenbank?

Auf dem Markt ist eine ganze Anzahl von Datenbanken verfügbar. Wenn Sie eine Einzelbenutzeranwendung erstellen müssen, die eigenständig auf einem einzelnen Computer läuft, können Sie die verschiedenen PC-basierten Datenbanken wie Access oder FoxPro von Microsoft oder Paradox von Borland ins Auge fassen. Bei Anwendungen, die auf große, gemeinsam genutzte Datenbanken zugreifen, kommt höchstwahrscheinlich nur eine SQL-basierte Datenbank wie SQL Server oder Oracle in Frage. Alle Datenbanken bieten grundsätzlich die gleiche Funktionalität, um Datensätze zu verwalten. Bei jeder Datenbank lassen sich je nach Bedarf einzelne oder mehrere Datensätze abrufen. Man kann auch beliebige Datensätze hinzufügen, aktualisieren oder löschen. Alle Datenbanken können die Anforderungen Ihrer Anwendungen erfüllen, so daß Sie in der Lage sein sollten, eine bestimmte Datenbank für die eine Anwendung einzusetzen und für die nächste Anwendung zu einer anderen Datenbank zu wechseln, je nachdem, welche konkreten Anforderungen in Ihrer Anwendung zu realisieren sind, welche Datenbank sich am besten für die Anwendung eignet, oder welche Datenbank Ihr Auftraggeber bevorzugt.

In der Praxis gibt es zahlreiche Unterschiede der heutzutage verfügbaren Datenbanken zu beachten. Jede Datenbank hat spezielle Stärken und Schwächen, was die eine Datenbank für eine bestimmte Situation geeigneter erscheinen läßt als eine andere. Allerdings würde es im Rahmen dieses Buches zu weit führen, auf die konkreten Unterschiede zwischen den einzelnen Produkten näher einzugehen. In bezug auf die heute und morgen zu behandelnden Datenbankfunktionen kann man davon ausgehen, daß alle Datenbanken funktionell gleichwertig und gegeneinander austauschbar sind.

Wenn man von einer Datenbank zu einer anderen wechselt, begegnet man dem Problem, daß jede Datenbank mit einer anderen Schnittstelle für den Zugriff arbeitet. Das bedeutet, daß man sich mit komplett neuen Programmierverfahren und Funktionen für jede einzusetzende Datenbank beschäftigen müßte. Diese Probleme lassen sich mit der eigens für diesen Zweck entwickelten ODBC-Schnittstelle in den Griff bekommen.

Die Schnittstelle ODBC

Microsoft hat die Inkompatibilität der Datenbankenschnittstellen als Problem erkannt. Jede Datenbank hatte ihre eigene Anwendungsentwicklungssprache, die zwar gut in die Datenbank integriert war, aber nicht mit irgendeiner anderen Datenbank zusammenarbeitete. Daraus ergaben sich für jeden Entwickler Probleme, der eine Datenbank für die eine Anwendung und dann eine andere Datenbank für die nächste Anwendung benötigte. Der Entwickler mußte sich mit der speziellen Datenbanksprache der jeweiligen Datenbank beschäftigen und konnte nicht auf eine bekannte Sprache zurückgreifen. Damit der Programmierer mit einer beliebigen Datenbank in der bevorzugten Programmiersprache arbeiten konnte, war eine standardisierte Schnittstelle erforderlich, die mit jeder Datenbank funktioniert.

Die Schnittstelle Open Database Connectivity (ODBC) ist als standardisierte, SQL-basierte Schnittstelle integriert und in das Betriebssystem Windows integriert. Hinter dieser Schnittstelle verbergen sich für die jeweilige Datenbank Plugins, die die ODBC- Funktionsaufrufe entgegennehmen und in Aufrufe für die spezielle Schnittstelle der betreffenden Datenbank umwandeln. Die ODBC-Schnittstelle verwendet auch einen zentralen Satz von Konfigurationen zur Datenbankverbindung, wobei auch die Art und Weise standardisiert ist, wie man diese Konfigurationen festlegt und verwaltet. Damit braucht der Programmierer nur noch eine einzige Datenbankschnittstelle für alle Datenbanken zu erlernen und einzusetzen. Darüber hinaus ist es den Anbietern von Programmiersprachen möglich, ODBC-Unterstützung in ihre Sprachen und Entwicklungswerkzeuge zu integrieren, um den Datenbankzugriff nahezu transparent zu gestalten.

Die Klasse CRecordset

In der Visual C++-Entwicklungsumgebung ist der größte Teil der ODBC-Funktionalität in zwei Klassen verkapselt: CRecordset und CDatabase. Die Klasse CDatabase enthält die Verbindungsinformationen zur Datenbank und kann in der gesamten Anwendung gemeinsam genutzt werden. Die Klasse CRecordset verkapselt einen Satz von Datensätze n aus der Datenbank. Über diese Klasse kann man eine auszuführende SQL-Abfrage spezifizieren. Die Klasse führt die Abfrage aus und verwaltet die Ergebnismenge, die die Datenbank zurückgibt. Die Datensätze im Recordset kann man modifizieren und aktualisieren, die Änderungen werden zurück an die Datenbank übergeben. Im Recordset lassen sich Datensätze hinzufügen und löschen. Auch diese Änderungen kann man zurück in die Datenbank schreiben.

Mit der Datenbank verbinden

Bevor die Klasse CRecordset irgendwelche Funktionen ausführen kann, muß sie mit einer Datenbank verbunden werden. Das realisiert man mit Hilfe der Klasse CDatabase . Es ist keine Instanz der Klasse CDatabase explizit zu erzeugen oder einzurichten - die erste Instanz der Klasse CRecordset übernimmt das automatisch. Wenn man eine Anwendung mit dem Anwendungs-Assistenten erstellt und die Einbindung der ODBC- Datenbankunterstützung wählt, bindet der Anwendungs-Assistent die Verbindungsinformationen zur Datenbank in die erste von ihm erzeugte und von CRecordset abgeleitete Klasse ein. Wenn man diese CRecordset-Klasse erzeugt, ohne ein CDatabase- Objekt zu übergeben, verwendet sie die vorgegebenen Verbindungsinformationen, die durch den Anwendungs-Assistenten hinzugefügt wurden, um ihre eigene Datenbankverbindung herzustellen.

Den Recordset öffnen und schließen

Nachdem das CRecordset-Objekt erstellt und mit der Datenbank verbunden ist, müssen Sie den Recordset öffnen, um die Gruppe der Datensätze aus der Datenbank abzurufen. Dazu verwenden Sie die Member-Funktion Open des CRecordset-Objekts. Diese Funktion kann man ohne irgendwelche Argumente aufrufen, wenn man für alles die Standardwerte übernehmen möchte, einschließlich der auszuführenden SQL- Anweisung.

Das erste Argument an die Funktion Open ist der Typ des Recordsets. Der Standardwert dafür lautet AFX_DB_USE_DEFAULT_TYPE. Er öffnet den Recordset als Snapshot von Datensätzen. Tabelle 14.1 listet die vier Typen von Recordsets auf. Nur zwei dieser Recordset-Typen sind im Anwendungs-Assistenten verfügbar, wenn Sie die Datenquelle spezifizieren.

Tabelle 14.1: Typen von Recordsets

Typ

Beschreibung

CRecordset::dynaset

Eine Gruppe von Datensätzen, die sich durch Aufruf der Funktion Fetch aktualisieren lassen, so daß Änderungen, die durch andere Benutzer am Recordset vorgenommen wurden, sichtbar sind.

CRecordset::snapshot

Eine Gruppe von Datensätzen, die sich nur aktualisieren läßt, wenn man den Recordset schließt und erneut öffnet.

CRecordset::dynamic

Nahezu ähnlich zum Typ CRecordset::dynaset, aber in vielen ODBC-Treibern nicht verfügbar.

CRecordset::forwardOnly

Eine schreibgeschützte Gruppe von Datensätzen, die sich nur vom ersten bis zum letzten Datensatz durchblättern lassen.

Das zweite Argument an die Funktion Open ist die SQL-Anweisung, die auszuführen ist, um den Recordset zu füllen. Übergibt man für dieses Argument eine NULL, wird die vom Anwendungs-Assistenten erzeugte und vorgegebene SQL-Anweisung ausgeführt.

Das dritte Argument ist eine Gruppe von Flags, mit denen Sie angeben können, wie die Gruppe der Datensätze in den Recordset abzurufen ist. Die meisten dieser Flags erfordern ein tiefergehendes Verständnis der ODBC-Schnittstelle, damit Sie Sinn und Zweck dieser Flags in Ihrer Anwendung einschätzen können. Aus diesem Grund zeigt Tabelle 14.2 lediglich ein paar dieser Flags.

Tabelle 14.2: Flags für das Öffnen eines Recordsets

Flag

Beschreibung

CRecordset::none

Der Standardwert für dieses Argument. Legt fest, daß keine Optionen die Art und Weise beeinflussen, wie der Recordset geöffnet und verwendet wird.

CRecordset::appendOnly

Verhindert, daß der Benutzer die existierenden Datensätze im Recordset bearbeiten oder löschen kann. Der Benutzer kann ausschließlich neue Datensätze in den Recordset einfügen. Diese Option kann nicht in Verbindung mit dem Flag CRecordset::readOnly verwendet werden.

CRecordset::readOnly

Legt fest, daß sich der Recordset nur lesen läßt und der Benutzer keinerlei Änderungen daran vornehmen kann. Diese Option kann nicht in Verbindung mit dem Flag CRecordset::appendOnly verwendet werden.

Nachdem der Benutzer die Arbeit mit dem Recordset abgeschlossen hat, können Sie die Funktion Close aufrufen, um den Recordset zu schließen und alle vom Recordset belegten Ressourcen freizugeben. Die Funktion Close übernimmt keine Argumente.

Durch den Recordset navigieren

Wenn Sie eine Gruppe von Datensätzen aus der Datenbank abgerufen haben, müssen Sie in der Lage sein, durch diese Menge von Datensätzen zu navigieren (es sei denn, Sie haben es nur mit einem einzigen Datensatz zu tun). Die Klasse CRecordset stellt mehrere Funktionen bereit, mit denen man im Recordset navigieren und den Benutzer zu einem beliebigen Datensatz führen kann. Tabelle 14.3 listet die verfügbaren Funktionen zur Navigation im Recordset auf.

Tabelle 14.3: Funktionen zur Navigation im Recordset

Funktion

Beschreibung

MoveFirst

Geht zum ersten Datensatz im Recordset.

MoveLast

Geht zum letzten Datensatz im Recordset.

MoveNext

Geht zum nächsten Datensatz im Recordset.

MovePrev

Geht zum vorherigen Datensatz im Recordset.

Move

Schaltet um die angegebene Zahl von Datensätzen ausgehend vom aktuellen Datensatz oder vom ersten Datensatz im Recordset weiter.

SetAbsolutePosition

Geht zum angegebenen Datensatz im Recordset.

IsBOF

Liefert TRUE zurück, wenn es sich beim aktuellen Datensatz um den ersten Datensatz im Recordset handelt.

IsEOF

Liefert TRUE, wenn es sich beim aktuellen Datensatz um den letzten Datensatz im Recordset handelt.

GetRecordCount

Gibt die Anzahl der Datensätze im Recordset zurück.

Nur zwei dieser Navigations- und Informationsfunktionen - Move und SetAbsolutePosition - weisen Argumente auf. Die Funktion SetAbsolutePosition übernimmt ein einzelnes numerisches Argument, das die Zeile des Zieldatensatzes spezifiziert. Bei Übergabe von 0 gelangen Sie zur Position BOF (Begin Of File - Dateianfang), bei 1 zum ersten Datensatz im Recordset. Negative Werte bewirken, daß vom letzten Datensatz im Recordset rückwärts gezählt wird. (Zum Beispiel kommen Sie mit -1 zum letzten, mit -2 zum vorletzten Datensatz.)

Die Funktion Move übernimmt zwei Argumente. Das erste gibt die Anzahl der zu überspringenden Zeilen an. Es lassen sich positive und negative Werte angeben. Mit negativen Werten navigieren Sie rückwärts durch den Recordset. Das zweite Argument gibt die Art und Weise der Navigation durch die Menge der Zeilen an. Die möglichen Werte für das zweite Argument sind in Tabelle 14.4 aufgeführt.

Tabelle 14.4: Navigationstypen in der Funktion Move

Typ

Beschreibung

SQL_FETCH_RELATIVE

Bewegung um die angegebene Anzahl von Zeilen ab der aktuellen Zeile.

SQL_FETCH_NEXT

Verschiebung zur nächsten Zeile, wobei die angegebene Anzahl von Zeilen ignoriert wird. Das gleiche wie der Aufruf der Funktion MoveNext.

SQL_FETCH_PRIOR

Verschiebung zur vorherigen Zeile, wobei die angegebene Anzahl von Zeilen ignoriert wird. Das gleiche wie der Aufruf der Funktion MovePrev.

SQL_FETCH_FIRST

Geht zur ersten Zeile, wobei die angegebene Anzahl von Zeilen ignoriert wird. Das gleiche wie der Aufruf der Funktion MoveFirst.

SQL_FETCH_LAST

Geht zur letzten Zeile, wobei die angegebene Anzahl der Zeilen ignoriert wird. Das gleiche wie der Aufruf der Funktion MoveLast.

SQL_FETCH_ABSOLUTE

Verschiebung um die angegebene Anzahl von Zeilen vom Beginn des Recordsets. Das gleiche wie der Aufruf der Funktion SetAbsolutePosition.

Datensätze hinzufügen, löschen und aktualisieren

In der Regel genügt es nicht, wenn man lediglich durch die Menge der Datensätze navigieren kann. Man muß auch in der Lage sein, neue Datensätze in den Recordset aufzunehmen, vorhandene Datensätze zu bearbeiten und zu aktualisieren sowie Datensätze zu löschen. Diese Aktionen sind alle möglich über die Funktionen, die die Klasse CRecordset bereithält. Die Funktionen, mit denen Sie diese Funktionalität realisieren können, sind in Tabelle 14.5 aufgeführt.

Tabelle 14.5: Bearbeitungsfunktionen für Recordsets

Funktion

Beschreibung

AddNew

Fügt einen neuen Datensatz in den Recordset ein.

Delete

Löscht den aktuellen Datensatz aus dem Recordset.

Edit

Erlaubt die Bearbeitung des aktuellen Datensatzes.

Update

Speichert die aktuellen Änderungen in der Datenbank.

Requery

Führt die aktuelle SQL-Abfrage erneut aus, um den Recordset zu aktualisieren.

Diese Funktionen weisen keine Argumente auf. Allerdings erfordern einige, daß man bestimmte Schritte einhält, damit die Funktionen ordnungsgemäß arbeiten können.

Um einen neuen Datensatz in die Datenbank aufzunehmen, rufen Sie die Funktion AddNew auf. Als nächstes müssen Sie Vorgabewerte in allen Feldern festlegen, die Werte erfordern, beispielsweise Schlüsselfelder. Dann ist die Funktion Update aufzurufen, um den neuen Datensatz in die Datenbank aufzunehmen. Wenn Sie versuchen, zu einem anderen Datensatz zu navigieren, bevor Sie die Funktion Update aufgerufen haben, geht der neue Datensatz verloren. Nachdem Sie den neuen Datensatz gespeichert haben, müssen Sie die Funktion Requery aufrufen, um den Recordset zu aktualisieren, damit Sie zum neuen Datensatz navigieren und dem Benutzer die Bearbeitung des neuen Datensatzes ermöglichen können. Diese Sequenz der Funktionsaufrufe sieht in der Regel folgendermaßen aus:

// Einen neuen Datensatz in den Recordset einfügen
m_pSet.AddNew();
// Das Schlüsselfeld auf den neuen Datensatz setzen
m_pSet.m_AddressID = m_lNewID;
// Den neuen Datensatz in der Datenbank speichern
m_pSet.Update();
// Den Recordset aktualisieren
m_pSet.Requery();
// Zum neuen Datensatz gehen
m_pSet.MoveLast();

Den aktuellen Datensatz können Sie einfach durch Aufruf der Funktion Delete löschen. Ist der aktuelle Datensatz gelöscht, müssen Sie zu einem anderen Datensatz navigieren, damit der Benutzer nicht mehr den gerade gelöschten Datensatz sieht. Sobald der aktuelle Datensatz gelöscht wurde, gibt es keinen aktuellen Datensatz mehr, bis Sie zu einem anderen Datensatz navigieren. Die Funktion Update müssen Sie nicht explizit aufrufen, weil das die Navigationsfunktionen automatisch erledigen. Damit läßt sich der folgende Code schreiben, um den aktuellen Datensatz zu löschen:

// Den aktuellen Datensatz löschen
m_pSet.Delete();
// Zum vorherigen Datensatz gehen
m_pSet.MovePrev();

Um schließlich dem Benutzer zu ermöglichen, den aktuellen Datensatz zu bearbeiten, rufen Sie die Funktion Edit auf. Damit können Sie die Felder im Datensatz mit den neuen, vom Benutzer eingegebenen oder durch Ihre Anwendung berechneten Werten aktualisieren. Nachdem alle Änderungen am aktuellen Datensatz ausgeführt sind, müssen Sie die Funktion Update aufrufen, um die Änderungen zu speichern:

// Dem Benutzer die Bearbeitung des aktuellen Datensatzes ermöglichen
m_pSet.Edit();
// Datenaustausch durchführen, dabei die Felder im Recordset aktualisieren
.
.
// Änderungen des Benutzers im aktuellen Datensatz speichern
m_pSet.Update();

Vielleicht fragen Sie sich, wie man zu den Feldern in den Datensätzen gelangt, um sie zu aktualisieren. Wenn der Anwendungs-Assistent die von CRecordset abgeleitete Klasse für Ihre Anwendung erstellt, fügt er alle Felder in den Datensätzen, die im Recordset erscheinen werden, als Member-Variablen der Recordset-Klasse hinzu. Im Ergebnis können Sie auf die Member-Variablen zugreifen, um die Datenelemente in den Datenbankdatensätzen, die Elemente des Recordsets sind, anzusprechen und zu manipulieren.

Eine Datenbankanwendung mit ODBC

Die heute zu erstellende Beispielanwendung konzipieren Sie als SDI-Anwendung mit ODBC-Datenbankunterstützung. Die Anwendung ruft Datensätze aus einer ODBC- Datenbank ab und erlaubt dem Benutzer, beliebige Datensätze zu bearbeiten und zu aktualisieren. Außerdem realisieren Sie die Funktionalität, um dem Benutzer zu ermöglichen, neue Datensätze in die Datenbank aufzunehmen und Datensätze aus der Datenbank zu löschen.

Die Datenbank vorbereiten

Bevor Sie eine Anwendung erstellen können, die eine Datenbank verwendet, brauchen Sie eine entsprechende Datenbank für Ihre Anwendung. Fast zu jeder Datenbank, die Sie für Ihre Anwendungen kaufen können, gehören Werkzeuge, mit denen sich eine neue Datenbank anlegen läßt. Zuerst müssen Sie Ihre Datenbank mit diesen Werkzeugen erstellen und dann mit dem ODBC-Administrator eine ODBC-Datenquelle für Ihre neue Datenbank konfigurieren.

Die neue Datenbank wurde für die Beispielanwendung in diesem Kapitel mit dem Datenbank-Assistent en von Access 97 erstellt. Als Vorlage für die Datenbank diente das Adreßbuch. Beim Start des Datenbank-Assistenten wählen Sie die vorgegebenen Felder, die in die Datenbank aufzunehmen sind, und die Option Beispieldaten einfügen, wie es Abbildung 14.1 zeigt. Übernehmen Sie die übrigen Einstellungen, die der Datenbank-Assistent vorgibt.

Abbildung 14.1:
Beispieldaten in die Datenbank aufnehmen

Nachdem Sie die Datenbank erstellt haben, müssen Sie eine ODBC-Datenquelle konfigurieren, die auf die gerade erstellte Datenbank verweist. Rufen Sie dazu den ODBC- Administrator auf, der sich in der Systemsteuerung von Windows 95/98 befindet.

Im Dialogfeld ODBC-Datenquellen-Administrator fügen Sie eine neue Datenquelle hinzu. Klicken Sie dazu auf die Schaltfläche Hinzufügen (siehe Abbildung 14.2). Es öffnet sich ein weiteres Dialogfeld, in dem Sie den Datenbanktreiber für die neue Datenquelle auswählen (siehe Abbildung 14.3).

Da Sie die heutige Beispielanwendung mit einer Access-Datenbank erstellen, markieren Sie den Microsoft Access-Treiber und klicken auf die Schaltfläche Fertigstellen.

Abbildung 14.2:
Der ODBC-Datenquellen-Administrator

Abbildung 14.3:
Das Dialogfeld Neue Datenquelle erstellen

Im Dialogfeld ODBC Microsoft Access 97-Setup (siehe Abbildung 14.4) geben Sie einen kurzen, einfachen Namen für die Datenquelle an. Ihre Anwendung verwendet diesen Namen, um die für die Datenbankverbindung zu verwendende Konfiguration der ODBC-Datenquelle zu spezifizieren. Daher sollte der Name den Zweck der Datenbank umreißen oder auf die Anwendung hinweisen, die mit der Datenbank arbeitet. Für die heutige Beispielanwendung wählen Sie etwa den Namen VCPP21DB (für Visual C++ in 21 Tagen, Datenbank) und geben dann eine Beschreibung für die Datenbank in das nächste Feld ein.

Abbildung 14.4:
Das Dialogfeld ODBC Microsoft Access 97-Setup

Nachdem Sie einen Namen und eine Beschreibung für die Datenquelle eingegeben haben, müssen Sie festlegen, wo sich die Datenbank befindet. Klicken Sie auf die Schaltfläche Auswählen, und spezifizieren Sie dann die Access-Datenbank, die Sie bereits erstellt haben. Nachdem Sie die ODBC-Datenquelle für Ihre Datenbank konfiguriert haben, klicken Sie auf die Schaltfläche OK, um die neue Datenquelle in den ODBC-Datenquellen-Administrator aufzunehmen. Klicken Sie erneut auf OK, um die Konfiguration zu beenden und den ODBC-Datenquellen-Administrator zu schließen, da Sie nun Ihre Aufmerksamkeit auf das Erstellen der Anwendung richten können.

Das Anwendungsgerüst erstellen

Die heutige Beispielanwendung legen Sie als SDI-Anwendung mit Datenbankunterstützung an. Beginnen Sie ein neues Projekt, wählen Sie den Anwendungs-Assistenten, und geben Sie einen passenden Namen wie etwa DbOdbc ein.

Im ersten Dialogfeld des Anwendungs-Assistenten wählen Sie die Option Einzelnes Dokument (SDI). Im zweiten Dialogfeld wählen Sie die Option Datenbankansicht mit Dateiunterstützung und klicken auf die Schaltfläche Datenquelle, um die Datenquelle für Ihre Anwendung festzulegen. Im Dialogfeld Datenbankoptionen klicken Sie auf die Option ODBC und wählen die für Ihre Access-Datenbank erstellte ODBC- Konfiguration aus dem Listenfeld aus, wie es Abbildung 14.5 zeigt. Als Recordset-Typ können Sie entweder Snapshot oder Dynaset wählen.

Abbildung 14.5:
Das Dialogfeld Datenbankoptionen

Wenn Sie auf OK klicken, erscheint ein weiteres Dialogfeld, in dem die verfügbaren Tabellen der ausgewählten Datenbank aufgelistet sind. Markieren Sie die Tabelle Adressen, wie es Abbildung 14.6 zeigt, und klicken Sie auf OK, um das Dialogfeld zu schließen und zum Anwendungs-Assistenten zurückzukehren.

Abbildung 14.6:
Das Dialogfeld Datenbanktabellen wählen

In den übrigen Dialogfeldern des Anwendungs-Assistenten übernehmen Sie die Standardeinstellungen. Das letzte Dialogfeld des Assistenten zeigt, daß der Assistent eine zusätzliche Klasse angelegt hat. Wenn Sie diese Klasse markieren, sehen Sie, daß sie von der Klasse CRecordset abgeleitet ist. Außerdem ist festzustellen, daß die Ansichtsklasse von der Klasse CRecordView abgeleitet ist, die ein Nachfolger der Klasse CFormView ist und zusätzlich die Datenbankunterstützung enthält.

Das Hauptformular entwerfen

Nachdem Sie das Anwendungsgerüst erstellt haben, entwerfen Sie das Layout des Hauptformulars, in dem Sie die Datensätze aus der Datenbank anzeigen und bearbeiten können. Dieses Formular läßt sich mit den Standardsteuerelementen von Visual C++ erstellen, ohne spezielle ActiveX-Steuerelemente zu benötigen. Für das Layout des Hauptformulars Ihrer Beispielanwendung können Sie sich an Abbildung 14.7 orientieren. Die Steuerelemente konfigurieren Sie mit den in Tabelle 14.6 angegebenen Eigenschaften.

Wenn Sie die Beispielanwendung etwas zeitsparender erstellen möchten, können Sie die meisten Steuerelemente und Datenbankfelder aus der Anwendung weglassen. Die benötigten Schlüsselfelder sind Adressen-Nr, Vorname, Nachname, Geburtsdatum und Karte senden. Auf die anderen Felder können Sie ohne weiteres verzichten.

Tabelle 14.6: Einstellungen der Eigenschaften für die Steuerelemente

Objekt

Eigenschaft

Einstellung

Text

ID

Titel

IDC_STATIC

Adressen-Nr:

Eingabefeld

ID

IDC_EID

Text

ID

Titel

IDC_STATIC

Vorname:

Eingabefeld

ID

IDC_EFNAME

Text

ID

Titel

IDC_STATIC

Nachname:

Eingabefeld

ID

IDC_ELNAME

Text

ID

Titel

IDC_STATIC

Name des Ehepartners:

Eingabefeld

ID

IDC_ESNAME

Text

ID

Titel

IDC_STATIC

Adresse:

Eingabefeld

ID

Mehrzeilig

IDC_EADDR

eingeschaltet

Text

ID

Titel

IDC_STATIC

Ort:

Eingabefeld

ID

IDC_ECITY

Text

ID

Titel

IDC_STATIC

Bundesland:

Eingabefeld

ID

IDC_ESTATE

Text

ID

Titel

IDC_STATIC

Postleitzahl:

Eingabefeld

ID

IDC_EZIP

Text

ID

Titel

IDC_STATIC

Land:

Eingabefeld

ID

IDC_ECOUNTRY

Text

ID

Titel

IDC_STATIC

Email-Adresse:

Eingabefeld

ID

IDC_EEMAIL

Text

ID

Titel

IDC_STATIC

Telefon/privat:

Eingabefeld

ID

IDC_EHPHONE

Text

ID

Titel

IDC_STATIC

Telefon/beruflich:

Eingabefeld

ID

IDC_EWPHONE

Text

ID

Titel

IDC_STATIC

Durchwahl Büro:

Eingabefeld

ID

IDC_EWEXT

Text

ID

Titel

IDC_STATIC

Faxnummer:

Eingabefeld

ID

IDC_EFAX

Text

ID

Titel

IDC_STATIC

Geburtsdatum:

Eingabefeld

ID

IDC_EDOB

Kontrollkästchen

ID

Titel

IDC_CBCARD

Karte senden

Text

ID

Titel

IDC_STATIC

Anmerkungen:

Eingabefeld

ID

Mehrzeilig

IDC_ENOTES

eingeschaltet

Abbildung 14.7:
Der Entwurf des Hauptformulars

Nachdem Sie alle Steuerelemente auf dem Hauptformular Ihrer Anwendung hinzugefügt und konfiguriert haben, können Sie die Steuerelemente mit den Feldern der Datenbank verbinden. Wenn Sie im Klassen-Assistenten auf die Registerkarte Member- Variablen gehen, ein Steuerelement markieren und auf die Schaltfläche Variable hinzufügen klicken, erscheint das Dialogfeld Member-Variable hinzufügen. Dieses Dialogfeld enthält ein Dropdown-Kombinationsfeld, in das Sie den Variablennamen eingeben können. Wenn Sie auf den Pfeil der Dropdown-Liste klicken, öffnet sich die Liste, die bereits mit den Feldern des Recordsets gefüllt ist, wie es Abbildung 14.8 zeigt. Damit können Sie die Datenbankfelder direkt mit den Steuerelementen auf dem Formular verbinden. Fügen Sie also die in Tabelle 14.7 angegebenen Variablen hinzu.

Tabelle 14.7: Variablen für die Steuerelemente des Hauptformulars

Objekt

Name

IDC_CBCARD

m_pSet->m_SendenKarte

IDC_EADDR

m_pSet->m_Adresse

IDC_ECITY

m_pSet->m_Ort

IDC_COUNTRY

m_pSet->m_Land

IDC_EEMAIL

m_pSet->m_EmailAdresse

IDC_EFAX

m_pSet->m_Faxnummer

IDC_EFNAME

m_pSet->m_Vorname

IDC_EHPHONE

m_pSet->m_TelefonPrivat

IDC_EID

m_pSet->m_Adressen_Nr

IDC_ELNAME

m_pSet->m_Nachname

IDC_ENOTES

m_pSet->m_Anmerkungen

IDC_ESNAME

m_pSet->m_EhepartnerName

IDC_ESTATE

m_pSet->m_Bundesland

IDC_EWEXT

m_pSet->m_Durchwahl_B_ro

IDC_EWPHONE

m_pSet->m_TelefonBeruflich

IDC_EZIP

m_pSet->m_Postleitzahl

Abbildung 14.8:
Das Dialogfeld Member-Variable hinzufügen mit Datensatzfeldern

Sicherlich haben Sie bemerkt, daß es in der Liste der Datenbankfelder kein Feld für das Geburtsdatum gibt, das Sie mit dem Steuerelement Geburtsdatum verbinden könnten. Wenn Sie sich die Recordset-Klasse in der Klassenansicht ansehen und den Baum erweitern, stellen Sie fest, daß das Geburtsdatum zwar als Datenbankfeld aufgeführt, aber nicht in der Liste der vorhandenen Spalten für die Steuerelemente verfügbar ist. Doppelklicken Sie in der Recordset-Klasse auf das Feld für das Geburtsdatum, um dessen Definition anzuzeigen. Hier ist zu sehen, daß die Variable m_Geburtsdatum mit dem Typ CTime deklariert ist. Aus diesem Grund ist die Variable nicht in der Liste der Datenbankfelder aufgeführt, die sich mit den Steuerelementen verbinden lassen. Es gibt weder ein Makro noch eine Funktion, mit denen man Daten zwischen einem Steuerelement und einer Variablen vom Typ CTime austauschen könnte. Das ist auch deshalb ein Problem, weil der Variablentyp CTime keine Datumswerte vor dem 31. Dezember 1969 behandeln kann. Um dieses Datenbankfeld nutzen zu können, muß man seine Definition vom Typ CTime in eine Variable vom Typ COleDateTime ändern, wie es in Zeile 17 von Listing 14.1 geschieht. Nachdem Sie den Variablentyp dieses Datenbankfelds geändert haben, können Sie auch die Variable mit dem Steuerelement IDC_EDOB verbinden.

Listing 14.1: Die Variablendeklarationen für die Datenbankfelder

1: // Feld-/Parameterdaten
2: //{{AFX_FIELD(CDbOdbcSet, CRecordset)
3: long m_Adressen_Nr;
4: CString m_Vorname;
5: CString m_Nachname;
6: CString m_EhepartnerName;
7: CString m_Adresse;
8: CString m_Ort;
9: CString m_Bundesland;
10: CString m_Postleitzahl;
11: CString m_Land;
12: CString m_EmailAdresse;
13: CString m_TelefonPrivat;
14: CString m_TelefonBeruflich;
15: CString m_Durchwahl_B_ro;
16: CString m_Faxnummer;
17: COleDateTime m_Geburtsdatum;
18: BOOL m_SendenKarte;
19: CString m_Anmerkungen;
20: //}}AFX_FIELD

Normalerweise tasten Sie die Codeabschnitte, die von den verschiedenen Assistenten erzeugt und verwaltet werden, nicht an. Die hier geschilderte Änderung gehört zu den wenigen Ausnahmen von dieser Regel. Man könnte dieses Hindernis als Bug von Visual C++ annehmen, obwohl es aus technischer Sicht kein Bug ist. Datenbankfelder für Datums-/Zeitwerte lassen sich in mehrere Variablentypen umwandeln, wenn man eine Klassenvariable erzeugt, die dieses Feld repräsentiert. CTime ist einer dieser Variablentypen, COleDateTime ein anderer. Da es sich bei beiden um gültige Auswahlen handelt und die Funktionen zum Füllen dieser Variablen mit beiden Typen arbeiten können, bleibt diese Änderung wahrscheinlich ohne gräßliche Konsequenzen.

Nachdem Sie den Variablentyp für die Variable m_Geburtsdatum in der Recordset- Klasse (CDbOdbcSet) geändert und dieses Datenbankfeld dem Steuerelement Geburtstag auf dem Formular zugeordnet haben, nehmen Sie vielleicht an, daß Sie die Anwendung nun kompilieren und ausführen können. Leider erhalten Sie eine Fehlermeldung des Compilers, daß DDX_FieldText den Variablentyp COleDateTime nicht konvertieren kann. Sie müssen also den Code zur Umwandlung in eigener Regie hinzufügen. Kehren Sie zum Klassen-Assistenten zurück, und löschen Sie die Variable, die Sie für das Steuerelement IDC_EDOB hinzugefügt haben. Nehmen Sie eine neue Variable für dieses Steuerelement auf. Legen Sie für die Variable den Typ COleDateTime fest, und geben Sie der Variablen einen Namen wie m_oledtDOB. Laden Sie die Funktion DoDataExchange der Sichtklasse (CDbOdbcView) in den Editor, und fügen Sie die Zeilen 4 bis 6 sowie die Zeilen 25 bis 28 gemäß Listing 14.2 in die Funktion ein.

Listing 14.2: Die Funktion DoDataExchange der Klasse CDbOdbcView

1: void CDbOdbcView::DoDataExchange(CDataExchange* pDX)
2: {
3: CRecordView::DoDataExchange(pDX);
4: // Geburtsdatum aus Recordset in Ansichtsvariable kopieren
5: if (pDX->m_bSaveAndValidate == FALSE)
6: m_oledtDOB = m_pSet->m_Geburtsdatum;
7: //{{AFX_DATA_MAP(CDbOdbcView)
8: DDX_FieldText(pDX, IDC_EADDR, m_pSet->m_Adresse, m_pSet);
9: DDX_FieldCheck(pDX, IDC_CBCARD, m_pSet->m_SendenKarte, m_pSet);
10: DDX_FieldText(pDX, IDC_ECITY, m_pSet->m_Ort, m_pSet);
11: DDX_FieldText(pDX, IDC_ECOUNTRY, m_pSet->m_Land, m_pSet);
12: DDX_FieldText(pDX, IDC_EEMAIL, m_pSet->m_EmailAdresse, m_pSet);
13: DDX_FieldText(pDX, IDC_EFAX, m_pSet->m_Faxnummer, m_pSet);
14: DDX_FieldText(pDX, IDC_EFNAME, m_pSet->m_Vorname, m_pSet);
15: DDX_FieldText(pDX, IDC_EHPHONE, m_pSet->m_TelefonPrivat, m_pSet);
16: DDX_FieldText(pDX, IDC_EID, m_pSet->m_Adressen_Nr, m_pSet);
17: DDX_FieldText(pDX, IDC_ELNAME, m_pSet->m_Nachname, m_pSet);
18: DDX_FieldText(pDX, IDC_ENOTES, m_pSet->m_Anmerkungen, m_pSet);
19: DDX_FieldText(pDX, IDC_ESNAME, m_pSet->m_EhepartnerName, m_pSet);
20: DDX_FieldText(pDX, IDC_ESTATE, m_pSet->m_Bundesland, m_pSet);
21: DDX_FieldText(pDX, IDC_EWEXT, m_pSet->m_Durchwahl_B_ro, m_pSet);
22: DDX_FieldText(pDX, IDC_EWPHONE, m_pSet->m_TelefonBeruflich, m_pSet);
23: DDX_FieldText(pDX, IDC_EZIP, m_pSet->m_Postleitzahl, m_pSet);
24: DDX_Text(pDX, IDC_EDOB, m_oledtDOB);
25: //}}AFX_DATA_MAP
26: // Geburtsdatum aus der Ansichtsvariablen zurück in den Recordset kopieren
27: if (pDX->m_bSaveAndValidate == TRUE)
28: m_pSet->m_Geburtsdatum = m_oledtDOB;
29: }

Zusätzlich zu den obigen Änderungen ist noch die Initialisierung der Variablen m_Geburtsdatum in der Recordset-Klasse zu entfernen. Diesen Code hat ebenfalls der Anwendungs-Assistenten hinzugefügt. Auch hier müssen Sie die Regel durchbrechen, den Code zu modifizieren, den Sie eigentlich niemals berühren sollten. Um diese Änderung durchzuführen, können Sie einfach die Initialisierung dieser Variablen im Konstruktor der Recordset-Klasse auskommentieren, wie es Zeile 19 von Listing 14.3 zeigt.

Listing 14.3: Der Konstruktor von CDbOdbcSet

1: CDbOdbcSet::CDbOdbcSet(CDatabase* pdb)
2: : CRecordset(pdb)
3: {
4: //{{AFX_FIELD_INIT(CDbOdbcSet)
5: m_Adressen_Nr = 0;
6: m_Vorname = _T("");
7: m_Nachname = _T("");
8: m_EhepartnerName = _T("");
9: m_Adresse = _T("");
10: m_Ort = _T("");
11: m_Bundesland = _T("");
12: m_Postleitzahl = _T("");
13: m_Land = _T("");
14: m_EmailAdresse = _T("");
15: m_TelefonPrivat = _T("");
16: m_TelefonBeruflich = _T("");
17: m_Durchwahl_B_ro = _T("");
18: m_Faxnummer = _T("");
19: //m_Geburtsdatum = 0;
20: m_SendenKarte = FALSE;
21: m_Anmerkungen = _T("");
22: m_nFields = 17;
23: //}}AFX_FIELD_INIT
24: m_nDefaultType = snapshot;
25: }

Jetzt können Sie die Anwendung erneut kompilieren und ausführen. Sie haben nun eine voll funktionsfähige Datenbankanwendung vor sich, die eine Menge von Datensätzen aus der Datenbank abruft und es ermöglicht, durch diese Datensätze zu blättern und Änderungen an den Daten vorzunehmen (siehe Abbildung 14.9).

Abbildung 14.9:
Die laufende Anwendung

Neue Datensätze hinzufügen

Sie haben bereits eine voll funktionsfähige Datenbankanwendung erstellt, ohne eine einzige Zeile Code zu schreiben. Allerdings fehlen noch ein paar Funktionen. In den meisten Datenbankanwendungen kann der Benutzer neue Datensätze in die Datenbank aufnehmen. Um einen neuen Datensatz in die Datenbank hinzuzufügen, müssen Sie herausfinden, wie die nächste ID-Nummer lauten soll. Gehen Sie zum letzten Datensatz im Recordset, um die ID zu ermitteln, und inkrementieren Sie diese um 1. Als nächstes rufen Sie die Funktion AddNew auf, um einen neuen Datensatz hinzuzufügen, setzen das ID-Feld auf die neu berechnete ID und rufen dann die Funktion Update auf, um den neuen Datensatz zu speichern. Schließlich rufen Sie die Funktion Requery auf, um die Ergebnismenge zu aktualisieren, und gehen dann zum letzten Datensatz im Recordset, um dem Benutzer die Eingabe von Daten in den neuen Datensatz anzubieten.

Da das ID-Feld in der Datenbank als AutoWert-Feld definiert ist, legen Sie normalerweise die ID für das Feld nicht selbst fest. Da allerdings der Recordset einen neuen Datensatz mit dem ID-Feld erzeugt, müssen Sie dem Datensatz eine gültige ID zuweisen, da Sie den Datensatz ansonsten nicht in die Datenbank aufnehmen können. Die in der Beispielanwendung verwendete Methode funktioniert nicht in einer Mehrbenutzerdatenbank, da jeder Benutzer dieselbe ID für neue Datensätze erzeugen würde. In dieser Situation stellt eine zentrale Methode für das Generieren neuer IDs, wie etwa ein Zählerfeld in der Datenbank, die bessere Lösung dar. Weiterhin haben Sie die Möglichkeit, eine SQL-Anweisung zu erstellen, die einen neuen Datensatz in die Datenbank einfügt. In dieser Anweisung lassen Sie das ID-Feld aus, so daß die AutoWert-Funktion korrekt arbeiten kann.

Um die beschriebene Funktionalität in der Beispielanwendung zu realisieren, fügen Sie zunächst in die Recordset-Klasse eine Funktion ein, mit der Sie die nächste zu verwendende ID-Nummer bestimmen. Nehmen Sie dazu eine Member-Funktion in die Recordset-Klasse (CDbOdbcSet) auf. Legen Sie den Funktionstyp als long, die Funktionsdeklaration mit GetMaxID und den Zugriffsstatus als Public fest. Schreiben Sie den Code gemäß Listing 14.4 in die Funktion.

Listing 14.4: Die Funktion GetMaxID der Klasse CDbOdbcSet

1: long CDbOdbcSet::GetMaxID()
2: {
3: // Zum letzten Datensatz gehen
4: MoveLast();
5: // ID dieses Datensatzes zurückgeben
6: return m_Adressen_Nr;
7: }

Als nächstes statten Sie das Menü Datensatz mit einem neuen Befehl aus, damit der Benutzer einen neuen Datensatz in die Datenbank aufnehmen kann. Konfigurieren Sie den neuen Menübefehl mit den Eigenschaften gemäß Tabelle 14.8.

Tabelle 14.8: Eigenschaftseinstellungen für das Menü

Objekt

Eigenschaft

Einstellung

Menübefehl

ID

Titel

Statuszeilentext

IDM_RECORD_NEW

Neuer &Datensatz

Fügt einen neuen Datensatz hinzu\nNeuer Datensatz

Mit dem Klassen-Assistenten erstellen Sie eine Behandlungsroutine für die Nachricht COMMAND dieses Menüs in der Ansichtsklasse CDbOdbcView. In die Funktion übernehmen Sie den Code aus Listing 14.5.

Listing 14.5: Die Funktion OnRecordNew der Klasse CDbOdbcView

1: void CDbOdbcView::OnRecordNew()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4: // Zeiger auf Recordset holen
5: CRecordset* pSet = OnGetRecordset();
6: // Sicherstellen, daß alle Änderungen am aktuellen
7: // Datensatz gespeichert wurden.
8: if (pSet->CanUpdate() && !pSet->IsDeleted())
9: {
10: pSet->Edit();
11: if (!UpdateData())
12: return;
13:
14: pSet->Update();
15: }
16: // ID für den neuen Datensatz ermitteln
17: long m_lNewID = m_pSet->GetMaxID() + 1;
18: // Den neuen Datensatz hinzufügen
19: m_pSet->AddNew();
20: // Die ID in den neuen Datensatz schreiben
21: m_pSet->m_Adressen_Nr = m_lNewID;
22: // Den neuen Datensatz speichern
23: m_pSet->Update();
24: // Den Recordset aktualisieren
25: m_pSet->Requery();
26: // Zum neuen Datensatz gehen
27: m_pSet->MoveLast();
28: // Formular aktualisieren
29: UpdateData(FALSE);
30: }

Korrespondierend zum Menübefehl Neuer Datensatz fügen Sie eine neue Schaltfläche in die Symbolleiste ein. Dann können Sie Ihre Anwendung kompilieren und ausführen. Nunmehr sollte es möglich sein, neue Datensätze in die Datenbank aufzunehmen, wobei Sie in die neuen Datensätze Daten eingeben können.

Datensätze löschen

Als letztes ist noch die Funktionalität zum Löschen des aktuellen Datensatzes aus der Datenbank zu implementieren. Um diese Aktion auszulösen, fügen Sie einen neuen Menübefehl hinzu. Wenn der Benutzer diesen Befehl wählt, fragen Sie zur Sicherheit nach, ob er den aktuellen Datensatz wirklich löschen möchte, und rufen dann die Funktion Delete auf, um den Datensatz zu entfernen. Anschließend rufen Sie die Funktion MovePrev auf, um zum vorherigen Datensatz im Recordset zu navigieren.

Diese Funktionalität realisieren Sie über einen neuen Menübefehl, den der Benutzer auswählen kann, um den aktuellen Datensatz aus der Datenbank zu löschen. Fügen Sie den neuen Befehl in das Menü Datensatz ein, und konfigurieren Sie den Befehl mit den Eigenschaften gemäß Tabelle 14.9.

Tabelle 14.9: Eigenschaftseinstellungen für das Menü

Objekt

Eigenschaft

Einstellung

Menübefehl

ID

Titel

Statuszeilentext

IDM_RECORD_DELETE

Datensatz l&öschen

Löscht den aktuellen Datensatz \nDatensatz löschen

Mit dem Klassen-Assistenten erstellen Sie eine Behandlungsroutine für die Nachricht COMMAND dieses Menübefehls in der Ansichtsklasse CDbOdbcView. In die Funktion schreiben Sie den Code aus Listing 14.6.

Listing 14.6: Die Funktion OnRecordDelete der Klasse CDbOdbcView

1: void CDbOdbcView::OnRecordDelete()
2: {
3: // TODO: Code für Befehlsbehandlungsroutine hier einfügen
4: // Fragen, ob Benutzer wirklich den Datensatz löschen will
5: if (MessageBox("Möchten Sie diesen Datensatz wirklich löschen?",
6: "Diesen Datensatz löschen?", MB_YESNO | MB_ICONQUESTION) == IDYES)
7: {
8: // Den Datensatz löschen
9: m_pSet->Delete();
10: // Zum vorherigen Datensatz gehen
11: m_pSet->MovePrev();
12: // Formular aktualisieren
13: UpdateData(FALSE);
14: }
15: }

In die Symbolleiste nehmen Sie eine neue Schaltfläche auf und verbinden sie mit der Menü-ID IDM_RECORD_DELETE, damit der Benutzer den aktuellen Datensatz löschen kann, ohne erst über das Menü zu gehen. Wenn Sie jetzt Ihre Anwendung kompilieren und ausführen, haben Sie eine voll funktionsfähige Datenbankanwendung vor sich, in der Sie Datensätze hinzufügen, bearbeiten und löschen können (siehe Abbildung 14.10).

Abbildung 14.10:
Die fertiggestellte Anwendung

Zusammenfassung

Die heutige Lektion hat gezeigt, wie man mit Hilfe der ODBC-Schnittstelle Datenbankanwendungen erstellt, die sich in Verbindung mit einer beliebigen Datenbank einsetzen lassen. Sie haben gesehen, wie die Klasse CRecordset einen Großteil der Funktionalität bereitstellt, so daß Sie Datenbankaktionen in Ihre Anwendungen einbauen können. Weiterhin wurde erläutert, wie der Anwendungs-Assistent bereits einen wesentlichen Teil der Datenbankfunktionalität realisiert, ohne daß Sie eine einzige Codezeile schreiben müssen.

Morgen geht es um die neueste Technologie für den Datenbankzugriff von Microsoft, ActiveX Data Objects. Sie werden erfahren, wie man diese Technologie in Verbindung mit der ODBC-Schnittstelle einsetzt, um den Zugriff auf Datenbanken noch leichter zu realisieren.

Fragen und Antworten

Frage:
Warum soll ich mit der ODBC-Schnittstelle arbeiten und nicht mit den Datenzugriffsobjekten (DAO)?

Antwort:
Die Datenzugriffsobjekte stützen sich auf die Microsoft Jet Database Engine, um den gesamten Datenbankzugriff durchzuführen. Durch den zusätzlichen Verwaltungsaufwand (Overhead) bläht sich Ihre Anwendung um mindestens 1 Mbyte auf. Falls Sie mit einer SQL-basierten Datenbank arbeiten, kann die Datenbank bereits alle Aufgaben realisieren, die die Jet Engine ausführt. Darüber hinaus verwendet die Jet Database Engine die ODBC-Schnittstelle, um auf SQL-basierte Datenbanken zuzugreifen. Solange Sie also mit PC-basierten Datenbanken wie Access, FoxPro oder Paradox arbeiten, erzielen Sie eine bessere Leistungsbilanz, wenn Sie direkt in eigener Regie über die ODBC- Schnittstelle arbeiten.

Frage:
Wie kann ich unterschiedliche Recordsets in eine MDI-Anwendung aufnehmen?

Antwort:
Mit dem Klassen-Assistenten können Sie zusätzliche, von CRecordset abgeleitete Klassen in ein MDI-Anwendungsprojekt aufnehmen. Dazu legen Sie fest, daß die neue Klasse eine MFC-Klasse ist und als Basisklasse die Klasse CRecordset verwendet. Der Klassen-Assistent fordert die Angabe der Datenquelle, genau wie Sie beim Anwendungs-Assistenten das Anwendungsgerüst für die heutige Beispielanwendung erstellt haben. Nachdem Sie die Recordset-Klasse erzeugt haben, können Sie eine neue Klasse auf die gleiche Weise anlegen, wobei Sie CRecordView als Basisklasse spezifizieren. Wenn Sie auf OK klicken, müssen Sie im Klassen-Assistenten festlegen, welche der Recordset-Klassen mit der neuen Datensatzansichtsklasse zu verwenden ist.

Workshop

Kontrollfragen

1. Wofür steht ODBC?

2. Mit welchen Funktionen können Sie durch den Recordset in einem CRecordset- Objekt navigieren?

3. Welche Ansichtsklasse sollten Sie für Ihre ODBC-Anwendung wählen?

4. Welche Funktionssequenz ist aufzurufen, um einen neuen Datensatz in einen Recordset einzufügen?

5. Welche Funktion müssen Sie aufrufen, bevor sich Felder im CRecordset-Objekt mit allen Änderungen aktualisieren lassen?

Übung

Fügen Sie einen Menübefehl und ein Dialogfeld hinzu, um dem Benutzer die Möglichkeit zu geben, eine Datensatznummer als Ziel einzugeben. Verschieben Sie dann den Datensatzzeiger auf diesen Datensatz.



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


Ein Imprint des Markt&Technik Buch- und Software-Verlag GmbH.
Elektronische Fassung des Titels: Visual C++ 6 in 21 Tagen, ISBN: 3-8272-2035-1