Skip to content

7. Zugriff auf die Datenbanken

7.1. Allgemeines

Es gibt zahlreiche Datenbanken für Windows-Plattformen. Um darauf zuzugreifen, nutzen die Anwendungen sogenannte Treiber (Drivers).

In der obigen Abbildung verfügt der Treiber über zwei Schnittstellen:

  • die Schnittstelle I1, die der Anwendung zur Verfügung steht
  • die Schnittstelle I2 zur Datenbank

Um zu vermeiden, dass eine für eine Datenbank B1 geschriebene Anwendung bei einer Migration auf eine andere Datenbank B2 neu geschrieben werden muss, wurden Standardisierungsbemühungen an der Schnittstelle I1 unternommen. Bei der Verwendung von Datenbanken mit „normalisierten“ Treibern wird die Datenbank B1 mit einem Treiber P1 bereitgestellt, die Datenbank B2 mit einem Treiber P2, und die Schnittstelle I1 dieser beiden Treiber ist identisch. Daher muss die Anwendung nicht neu geschrieben werden. So kann man beispielsweise eine Datenbank ACCESS auf eine Datenbank MySQL migrieren, ohne die Anwendung zu ändern.

Es gibt zwei Arten von standardisierten Treibern:

  • die Treiber ODBC (Open DataBase Connectivity)
  • die Treiber OLE und DB (Object Linking and Embedding DataBase)

Die Treiber ODBC ermöglichen den Zugriff auf Datenbanken. Die Datenquellen für die Treiber OLE und DB sind vielfältiger: Datenbanken, E-Mail-Systeme, Verzeichnisse usw. Es gibt keine Einschränkungen. Jede Datenquelle kann Gegenstand eines Treibers OLE oder DB sein, wenn ein Hersteller dies beschließt. Der Nutzen ist offensichtlich groß: Man erhält einen einheitlichen Zugriff auf eine große Vielfalt an Daten.

Die Plattform .NET wird mit zwei Arten von Datenzugriffsklassen ausgeliefert:

  1. die Klassen SQL und Server.NET
  2. die Klassen OLE und Db.NET

Die ersten Klassen ermöglichen einen direkten Zugriff auf den Microsoft-Server SGBD SQL ohne zwischengeschalteten Treiber. Die zweiten Klassen ermöglichen den Zugriff auf die Datenquellen OLE DB.

Image

Die Plattform .NET wird (Stand: Mai 2002) mit drei Treibern OLE, DB für jeweils: SQL Server, Oracle und Microsoft Jet (Access) ausgeliefert. Wenn man mit einer Datenbank arbeiten möchte, für die ein Treiber ODBC, aber kein Treiber OLE oder DB vorhanden ist, ist dies nicht möglich. So kann man nicht mit SGBD und MySQL arbeiten, da diese (Stand Mai 2002) keine Treiber OLE und DB bereitstellen. Es gibt jedoch eine Reihe von Klassen, die den Zugriff auf die Datenquellen ermöglichen: die ODBC- und odbc.net-Klassen. Diese sind nicht standardmäßig im Lieferumfang des SDK enthalten und müssen von der Microsoft-Website heruntergeladen werden. In den folgenden Beispielen werden wir vor allem diese Klassen verwenden, da die meisten Datenbanken unter Windows mit einem solchen Treiber ausgeliefert werden. Hier ist beispielsweise eine Liste der auf einem Win 2000-Rechner installierten Treiber ODBC (Startmenü/Einstellungen/Systemsteuerung/Verwaltung):

Image

Wählen Sie das Symbol „Datenquelle“ ODBC aus:

Image

7.2. Die beiden Betriebsmodi einer Datenquelle

Die Plattform .NET ermöglicht die Nutzung einer Datenquelle auf zwei verschiedene Arten:

  1. Online-Modus
  2. Offline-Modus

Im Online-Modus

  1. eine Verbindung zur Datenquelle
  2. arbeitet mit der Datenquelle im Lese-/Schreibmodus
  3. schließt die Verbindung

Im Offline-Modus führt die Anwendung folgende Schritte aus:

  1. eine Verbindung zur Datenquelle auf
  2. ruft eine Speicherkopie aller oder eines Teils der Daten aus der Quelle ab
  3. schließt die Verbindung
  4. arbeitet mit der Speicherkopie der Daten im Lese-/Schreibmodus
  5. sobald die Arbeit abgeschlossen ist, eine Verbindung herstellt, die geänderten Daten an die Datenquelle sendet, damit diese sie berücksichtigt, und die Verbindung schließt

In beiden Fällen ist es die Verarbeitung und Aktualisierung der Daten, die Zeit in Anspruch nimmt. Stellen wir uns vor, diese Aktualisierungen würden von einem Benutzer vorgenommen, der Daten eingibt – dieser Vorgang kann Dutzende von Minuten dauern. Während dieser gesamten Zeit bleibt im verbundenen Modus die Verbindung zur Datenbank aufrechterhalten und die Änderungen werden sofort übernommen. Im nicht verbundenen Modus besteht während der Datenaktualisierung keine Verbindung zur Datenbank. Die Änderungen werden ausschließlich an der Speicherkopie vorgenommen. Sie werden erst nach Abschluss aller Vorgänge in einem Schritt an die Datenquelle übertragen.

Was sind die Vor- und Nachteile der beiden Methoden?

  • Eine Verbindung beansprucht viele Systemressourcen. Bei vielen gleichzeitigen Verbindungen lässt sich im Offline-Modus deren Dauer auf ein Minimum reduzieren. Dies ist beispielsweise bei Webanwendungen mit Tausenden von Nutzern der Fall.
  • Der Nachteil des Offline-Modus ist die schwierige Handhabung gleichzeitiger Aktualisierungen. Der Benutzer U1 ruft zum Zeitpunkt T1 Daten ab und beginnt, diese zu ändern. Zum Zeitpunkt T2 greift auch der Benutzer U2 auf die Datenquelle zu und erhält dieselben Daten. In der Zwischenzeit hat der Benutzer U1 bestimmte Daten geändert, diese jedoch noch nicht an die Datenquelle übertragen. U2 arbeitet daher mit Daten, von denen einige fehlerhaft sind. Die Klassen .NET bieten Lösungen zur Bewältigung dieses Problems, doch es ist nicht einfach zu lösen.
  • Im verbundenen Modus stellt die gleichzeitige Aktualisierung von Daten durch mehrere Benutzer normalerweise kein Problem dar. Da die Verbindung zur Datenbank aufrechterhalten bleibt, verwaltet die Datenbank selbst diese gleichzeitigen Aktualisierungen. So sperrt Oracle eine Zeile in der Datenbank, sobald ein Benutzer sie ändert. Sie bleibt gesperrt und ist somit für andere Benutzer unzugänglich, bis derjenige, der sie geändert hat, seine Änderung bestätigt (Commit) oder rückgängig macht (Rollback).
  • Wenn die Daten über das Netzwerk übertragen werden sollen, ist der Offline-Modus zu wählen. Er ermöglicht es, eine Momentaufnahme der Daten in einem Objekt namens „Dataset“ zu erhalten, das eine eigenständige Datenbank darstellt. Dieses Objekt kann über das Netzwerk zwischen Rechnern übertragen werden.

Wir befassen uns zunächst mit dem verbundenen Modus.

7.3. Datenzugriff im verbundenen Modus

7.3.1. Die Datenbanken des Beispiels

Wir betrachten eine Datenbank mit dem Namen ACCESS, die als articles.mdb bezeichnet wird und nur eine Tabelle namens ARTICLES mit folgender Struktur enthält:

name
Typ
Code
4-stelliger Artikelcode
Name
Name (Zeichenkette)
Preis
sein Preis (tatsächlicher Preis)
stock_actuel
sein aktueller Lagerbestand (Ganzzahl)
stock_minimum
der Mindestbestand (ganze Zahl), unterhalb dessen der Artikel nachbestellt werden muss

Der Ausgangsinhalt lautet wie folgt:

Image

Wir werden diese Grundlage sowohl anhand eines Testartikels ODBC als aucheinen Treiber OLE DB verwenden, um die Ähnlichkeit der beiden Ansätze aufzuzeigen und weil uns diese beiden Treiberarten für ACCESS zur Verfügung stehen.

Wir werden außerdem eine Datenbank MySQL DBARTICLES verwenden, die dieselbe einzige Tabelle ARTICLES enthält, denselben Inhalt und auf die über einen Treiber ODBC zugegriffen wird, um zu zeigen, dass die Anwendung, die für die Nutzung der Datenbank ACCESS geschrieben wurde, nicht geändert werden muss, um die Datenbank MySQL zu verwenden. Auf die Datenbank DBARTICLES kann ein Benutzer namens admarticles mit dem Passwort mdparticles zugreifen. Der folgende Screenshot zeigt den Inhalt der Datenbank MySQL:

C:\mysql\bin>mysql --database=dbarticles --user=admarticles --password=mdparticles
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3 to server version: 3.23.49-max-debug

Type 'help' for help.


mysql> show tables;
+----------------------+
| Tables_in_dbarticles |
+----------------------+
| articles             |
+----------------------+
1 row in set (0.01 sec)

mysql> select * from articles;
+------+--------------------------------+------+--------------+---------------+
| code | nom                            | prix | stock_actuel | stock_minimum |
+------+--------------------------------+------+--------------+---------------+
| a300 | vÚlo                           | 2500 |           10 |             5 |
| b300 | pompe                          |   56 |           62 |            45 |
| c300 | arc                            | 3500 |           10 |            20 |
| d300 | flÞches - lot de 6             |  780 |           12 |            20 |
| e300 | combinaison de plongÚe         | 2800 |           34 |             7 |
| f300 | bouteilles d'oxygÞne           |  800 |           10 |             5 |
+------+--------------------------------+------+--------------+---------------+
6 rows in set (0.02 sec)

mysql> describe articles;
+---------------+-------------+------+-----+---------+-------+
| Field         | Type        | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| code          | text        | YES  |     | NULL    |       |
| nom           | text        | YES  |     | NULL    |       |
| prix          | double      | YES  |     | NULL    |       |
| stock_actuel  | smallint(6) | YES  |     | NULL    |       |
| stock_minimum | smallint(6) | YES  |     | NULL    |       |
+---------------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> exit
Bye

Um die Basis ACCESS als Datenquelle ODBC zu definieren, gehen Sie wie folgt vor:

  • Rufen Sie den Datenquellen-Manager ODBC wie oben gezeigt auf und wählen Sie die Registerkarte „User“ DSN (DSN = Name der Datenquelle)

Image

  • Fügen Sie über die Schaltfläche Add eine Quelle hinzu, geben Sie an, dass diese Quelle über einen Treiber Access zugänglich ist, und führen Sie Terminer aus:

Image

  • Geben Sie der Datenquelle den Namen articles-access, fügen Sie eine beliebige Beschreibung hinzu und verwenden Sie die Schaltfläche Sélectionner, um die Datei .mdb aus der Datenbank anzugeben. Beenden Sie den Vorgang mit OK.

Image

Die neue Datenquelle erscheint dann in der Liste der Benutzerquellen DSN:

Image

Um die Datenbank MySQL DBARTICLES als Datenquelle ODBC zu definieren, gehen Sie wie folgt vor:

  • Öffnen Sie den Datenquellen-Manager ODBC wie oben gezeigt und wählen Sie die Registerkarte „User“ (Benutzer) DSN aus. Fügen Sie eine neue Datenquelle mit Add hinzu und wählen Sie den Treiber ODBC von MySQL aus.

Image

  • Führen Sie Terminer aus. Daraufhin erscheint eine Konfigurationsseite für die Quelle MySQL:

54321

Image

  • In (1) vergeben wir einen Namen für unsere Datenquelle ODBC
  • In (2) geben wir den Rechner an, auf dem sich der Server MySQL befindet. Hier geben wir localhost ein, um anzugeben, dass er sich auf demselben Rechner wie unsere Anwendung befindet. Befände sich der Server MySQL auf einem entfernten Rechner M, würden wir dort dessen Namen eingeben, und unsere Anwendung würde dann ohne Änderungen mit einer entfernten Datenbank arbeiten.
  • In (3) geben wir den Namen der Datenbank ein. Hier heißt sie DBARTICLES.
  • In (4) geben wir den Benutzernamen admarticles und in (5) das Passwort mdparticles ein.

7.3.2. Verwendung eines Treibers ODBC

In einer Anwendung, die eine Datenbank im verbundenen Modus nutzt, sind in der Regel folgende Schritte erforderlich:

  1. Verbindung zur Datenbank
  2. Senden von Abfragen SQL an die Datenbank
  3. Empfang und Verarbeitung der Ergebnisse dieser Abfragen
  4. Schließen der Verbindung

Die Schritte 2 und 3 werden wiederholt ausgeführt, wobei das Schließen der Verbindung erst am Ende der Datenbanknutzung erfolgt. Dies ist ein relativ klassisches Schema, mit dem Sie vielleicht bereits vertraut sind, wenn Sie schon einmal eine Datenbank interaktiv genutzt haben. Diese Schritte sind dieselben, unabhängig davon, ob die Datenbank über den Treiber ODBC oder über die Treiber OLE bzw. DB genutzt wird. Im Folgenden stellen wir ein Beispiel mit den Klassen .NET zur Verwaltung der Datenquellen ODBC vor. Das Programm heißt liste und nimmt als Parameter den Namen DSN einer Datenquelle ODBC entgegen, die eine Tabelle ARTICLES enthält. Anschließend zeigt es den Inhalt dieser Tabelle an:

dos>liste
syntaxe : pg dsnArticles

dos>liste articles-access

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

dos>liste mysql-artices
Erreur d'exploitation de la base de données (ERROR [IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified)

dos>liste mysql-articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

Aus den obigen Ergebnissen geht hervor, dass das Programm sowohl den Inhalt der Datenbank ACCESS als auch den der Datenbank MySQL aufgelistet hat. Sehen wir uns nun den Code dieses Programms an:


' Optionen
Option Explicit On 
Option Strict On

' Namensräume
Imports System
Imports System.Data
Imports Microsoft.Data.Odbc
Imports Microsoft.VisualBasic

Module db1
    Sub main(ByVal args As String())
        ' Konsolenanwendung
        ' zeigt den Inhalt einer Tabelle ARTICLES aus einer Datenbank DSN an 
        ', deren Name als Parameter übergeben wurde
        Const syntaxe As String = "syntaxe : pg dsnArticles"
        Const tabArticles As String = "articles"        ' la table des articles

        ' Überprüfung der Parameter
        ' Gibt es einen Parameter?
        If args.Length <> 1 Then
            ' Fehlermeldung
            Console.Error.WriteLine(syntaxe)
            ' Ende
            Environment.Exit(1)
        End If

        ' Der Parameter wird abgerufen
        Dim dsnArticles As String = args(0)                ' la base DSN
        ' Vorbereitung der Datenbankverbindung
        Dim articlesConn As OdbcConnection = Nothing        ' la connexion
        Dim myReader As OdbcDataReader = Nothing            ' le lecteur de données

        ' Zugriff auf die Datenbank wird versucht
        Try
            ' Verbindungszeichenfolge zur Datenbank
            Dim connectString As String = "DSN=" + dsnArticles + ";"
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()

            ' Ausführung eines Befehls SQL
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOdbcCommand As New OdbcCommand(sqlText)
            myOdbcCommand.Connection = articlesConn
            myReader = myOdbcCommand.ExecuteReader()

            ' Auswertung der abgerufenen Tabelle
            ' Anzeige der Spalten
            Dim ligne As String = ""
            Dim i As Integer
            For i = 0 To (myReader.FieldCount - 1) - 1
                ligne += myReader.GetName(i) + ","
            Next i
            ligne += myReader.GetName(i)
            Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))

            ' Anzeige der Daten
            While myReader.Read()
                ' Auswertung der aktuellen Zeile
                ligne = ""
                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i
                Console.WriteLine(ligne)
            End While
        Catch ex As Exception
            Console.Error.WriteLine(("Erreur d'exploitation de la base de données " + ex.Message + ")"))
            Environment.Exit(2)
        Finally
            ' Leser schließen
            myReader.Close()
            ' Verbindung schließen
            articlesConn.Close()
        End Try
    End Sub
End Module

Die Klassen zur Verwaltung der Quellen ODBC befinden sich im Namensraum Microsoft.Data.Odbc, der daher importiert werden muss. Außerdem befinden sich einige Klassen im Namensraum System.Data.


Imports System.Data
Imports Microsoft.Data.Odbc

Die vom Programm verwendeten Namensräume befinden sich in verschiedenen Assemblies. Das Programm wird mit dem folgenden Befehl kompiliert:

dos>vbc /r:microsoft.data.odbc.dll /r:microsoft.visualbasic.dll /r:system.dll /r:system.data.dll db1.vb

7.3.2.1. Die Verbindungsphase

Eine Verbindung ODBC verwendet die Klasse OdbcConnection. Der Konstruktor dieser Klasse akzeptiert als Parameter eine sogenannte Verbindungszeichenfolge. Dabei handelt es sich um eine Zeichenfolge, die alle notwendigen Parameter definiert, damit die Verbindung zur Datenbank hergestellt werden kann. Diese Parameter können sehr zahlreich sein, wodurch die Zeichenfolge komplex werden kann. Die Zeichenfolge hat die Form "param1=valeur1;param2=valeur2;...;paramj=valeurj;". Hier sind einige mögliche Parameter für paramj:

uid
Name eines Benutzers, der auf die Datenbank zugreifen wird
password
Passwort dieses Benutzers
dsn
Name der Datenbank (falls vorhanden): DSN
data source
Name der Datenbank, auf die zugegriffen wird
...
 

Wenn man eine Datenquelle mithilfe des Datenquellen-Managers ODBC als Datenquelle ODBC definiert, wurden diese Parameter bereits angegeben und gespeichert. Es reicht dann aus, den Parameter DSN zu übergeben, der den Namen DSN der Datenquelle angibt. Dies geschieht hier wie folgt:


        ' Vorbereitung der Datenbankverbindung
        Dim articlesConn As OdbcConnection = Nothing        ' la connexion
        Dim myReader As OdbcDataReader = Nothing        ' le lecteur de données
        Try
            ' Zugriff auf die Datenbank wird versucht
            ' Verbindungszeichenfolge zur Datenbank
            Dim connectString As String = "DSN=" + dsnArticles + ";"
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()

Sobald das Objekt OdbcConnection erstellt ist, wird die Verbindung mit der Methode Open geöffnet. Diese Verbindung kann wie jeder andere Vorgang in der Datenbank fehlschlagen. Aus diesem Grund befindet sich der gesamte Code für den Datenbankzugriff in einem try-catch. Sobald die Verbindung hergestellt ist, können Abfragen vom Typ SQL an die Datenbank gesendet werden.

7.3.2.2. Abfragen vom Typ SQL senden

Um Abfragen vom Typ SQL auszuführen, benötigen wir ein Objekt vom Typ Command, genauer gesagt ein Objekt vom Typ OdbcCommand, da wir eine Datenquelle vom Typ ODBC verwenden. Die Klasse OdbcCommand verfügt über mehrere Konstruktoren:

  • OdbcCommand(): Erstellt ein leeres Objekt vom Typ Command. Um es zu verwenden, müssen später verschiedene Eigenschaften festgelegt werden:
    • CommandText: der Text der auszuführenden Abfrage SQL
    • Connection: das Objekt OdbcConnection, das die Verbindung zur Datenbank darstellt, auf der die Abfrage ausgeführt wird
    • CommandType: Der Typ der Abfrage SQL. Es gibt drei mögliche Werte
  1. CommandType.Text: Die Eigenschaft CommandText enthält den Text einer Abfrage vom Typ SQL (Standardwert)
  2. CommandType.StoredProcedure: Die Eigenschaft CommandText enthält den Namen einer in der Datenbank gespeicherten gespeicherten Prozedur
  3. CommandType.TableDirect: Die Eigenschaft CommandText enthält den Namen einer Tabelle T. Entspricht „select * from T“. Existiert nur für die Treiber OLE und DB.
  • OdbcCommand(string sqlText): Der Parameter sqlText wird der Eigenschaft CommandText zugewiesen. Dies ist der Text der auszuführenden Abfrage SQL. Die Verbindung muss in der Eigenschaft Connection angegeben werden.
  • OdbcCommand(string sqlText, OdbcConnection Verbindung): Der Parameter sqlText wird der Eigenschaft CommandText zugewiesen und der Parameter connexion der Eigenschaft Connection.

Um die Abfrage SQL auszuführen, stehen zwei Methoden zur Verfügung:

  • OdbcdataReader ExecuteReader(): sendet die Abfrage SELECT von CommandText an die Verbindung Connection und erstellt ein Objekt OdbcDataReader, das denZugriff auf alle Zeilen der Ergebnistabelle von select
  • int ExecuteNOnQuery(): Sendet die Aktualisierungsanfrage (INSERT, UPDATE, DELETE) von CommandText an die Verbindung Connection und gibt die Anzahl der von dieser Aktualisierung betroffenen Zeilen zurück.

In unserem Beispiel senden wir nach dem Öffnen der Datenbankverbindung eine Abfrage SQL SELECT, um den Inhalt der Tabelle ARTICLES abzurufen:


            ' Ausführung eines Befehls SQL
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOdbcCommand As New OdbcCommand(sqlText)
            myOdbcCommand.Connection = articlesConn
            myReader = myOdbcCommand.ExecuteReader()

Eine Abfrage ist in der Regel eine Abfrage vom Typ:

    select col1, col2,... from table1, table2,...
    where condition
    order by expression
    ...

Nur die Schlüsselwörter in der ersten Zeile sind obligatorisch, die anderen sind optional. Es gibt weitere Schlüsselwörter, die hier nicht aufgeführt sind.

  1. Es wird eine Verknüpfung mit allen Tabellen hergestellt, die hinter dem Schlüsselwort „from“ stehen
  2. Nur die Spalten, die hinter dem Schlüsselwort „select“ stehen, werden beibehalten
  3. Es werden nur die Zeilen beibehalten, die die Bedingung des Schlüsselworts „where“ erfüllen
  4. Die resultierenden Zeilen, sortiert nach dem Ausdruck des Schlüsselworts „order by“, bilden das Ergebnis der Abfrage.

Das Ergebnis von „select“ ist eine Tabelle. Wenn man die vorherige Tabelle „ARTICLES“ betrachtet und die Namen der Artikel ermitteln möchte, deren aktueller Lagerbestand unter dem Mindestschwellenwert liegt, schreibt man:

    select nom from articles where stock_actuel<stock_minimum

Wenn man sie in alphabetischer Reihenfolge der Namen haben möchte, schreibt man:

    select nom from articles where stock_actuel<stock_minimum order by nom

7.3.2.3. Auswertung des Ergebnisses einer Abfrage SELECT

Das Ergebnis einer Abfrage SELECT im Offline-Modus ist ein Objekt DataReader, hier ein Objekt OdbcDataReader. Mit diesem Objekt lassen sich nacheinander alle Zeilen des Ergebnisses abrufen und Informationen zu den Spalten dieser Ergebnisse erhalten. Sehen wir uns einige Eigenschaften und Methoden dieser Klasse an:

FieldCount
die Anzahl der Spalten in der Tabelle
Item
Item(i) steht für die Spalte Nr. i der aktuellen Zeile des Ergebnisses
XXX GetXXX(i)
Der Wert der Spalte Nr. i der aktuellen Zeile, dargestellt als Typ XXX (Int16, Int32, Int64, Double, String, Boolean, ...)
string GetName(i)
Name der Spalte Nr. i
Close()
schließt das Objekt OdbcdataReader und gibt die zugehörigen Ressourcen frei
bool Read()
Wechselt in der Ergebnistabelle um eine Zeile weiter. Gibt „false“ zurück, wenn dies nicht möglich ist. Die neue Zeile wird zur aktuellen Zeile des Lesers.

Die Auswertung des Ergebnisses eines select erfolgt typischerweise sequenziell, ähnlich wie bei Textdateien: Man kann sich in der Tabelle nur vorwärts bewegen, nicht rückwärts:


While myReader.Read()
    ' Es liegt eine Zeile vor – diese wird ausgewertet
    ....
    ' nächste Zeile
end while

Diese Erläuterungen reichen aus, um den folgenden Code aus unserem Beispiel zu verstehen:


            ' Auswertung der abgerufenen Tabelle
            ' Anzeige der Spalten
            Dim ligne As String = ""
            Dim i As Integer
            For i = 0 To (myReader.FieldCount - 1) - 1
                ligne += myReader.GetName(i) + ","
            Next i
            ligne += myReader.GetName(i)
            Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))

            ' Anzeige der Daten
            While myReader.Read()
                ' Auswertung der aktuellen Zeile
                ligne = ""
                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i
                Console.WriteLine(ligne)
            End While

Die einzige Schwierigkeit liegt in der Anweisung, in der die Werte der verschiedenen Spalten der aktuellen Zeile verkettet werden:


                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i

Die Notation „Zeile+=myReader(i).ToString“ wird übersetzt als „Zeile+=myReader.Item(i)“.ToString(), wobei Item(i) der Wert der Spalte i der aktuellen Zeile ist.

7.3.2.4. Freigabe von Ressourcen

Die Klassen OdbcReader und OdbcConnection verfügen beide über eine Methode Close(), die die mit den so geschlossenen Objekten verbundenen Ressourcen freigibt.

                ' Leser schließen
                myReader.Close()
                ' Verbindung schließen
                articlesConn.Close()

7.3.3. Verwendung eines Treibers OLE DB

Wir greifen dasselbe Beispiel wieder auf, diesmal mit einer Datenbank, auf die über einen Treiber OLE DB zugegriffen wird. Die Plattform .NET stellt einen solchen Treiber für Datenbanken vom Typ ACCESS bereit. Daher verwenden wir dieselbe Datenbank articles.mdb wie zuvor. Wir möchten hier zeigen, dass sich zwar die Klassen ändern, die Konzepte jedoch dieselben bleiben:

  • Die Verbindung wird durch ein Objekt OleDbConnection dargestellt
  • eine Abfrage SQL wird mithilfe eines Objekts OleDbCommand gesendet
  • Wenn es sich bei dieser Abfrage um eine Klausel SELECT handelt, wird als Rückgabewert ein Objekt OleDbDataReader zurückgegeben, um auf die Zeilen der Ergebnistabelle zuzugreifen

Diese Klassen befinden sich im Namensraum System.Data.OleDb. Das vorstehende Programm lässt sich leicht so umgestalten, dass es eine Datenbank vom Typ OLE DB verarbeitet:

  • Man ersetzt überall OdbcXX durch OleDbXX
  • die Verbindungszeichenfolge wird angepasst. Für eine Datenbank mit der Kennung ACCESS ohne Login/Passwort lautet die Verbindungszeichenfolge Provider=Microsoft.JET.OLEDB.4.0;Data Source=[fichier.mdb]. Der konfigurierbare Teil dieser Zeichenfolge ist der Name der zu verwendenden Datei ACCESS. Wir werden unser Programm so anpassen, dass es den Namen dieser Datei als Parameter akzeptiert.
  • Der zu importierende Namespace lautet nun System.Data.OleDb.

Unser Programm sieht nun wie folgt aus:


' Optionen
Option Explicit On 
Option Strict On

' Namensräume
Imports System
Imports System.Data
Imports Microsoft.Data.Odbc
Imports Microsoft.VisualBasic
Imports System.Data.OleDb

Module db2
    Public Sub Main(ByVal args() As String)

        ' Konsolenanwendung
        ' zeigt den Inhalt einer Tabelle ARRTICLES aus einer Datenbank DSN an 
        ', deren Name als Parameter übergeben wurde
        Const syntaxe As String = "syntaxe : pg base_access_articles"
        Const tabArticles As String = "articles"        ' la table des articles

        ' Überprüfung der Parameter
        ' Gibt es einen Parameter?
        If args.Length <> 1 Then
            ' Fehlermeldung
            Console.Error.WriteLine(syntaxe)
            ' Ende
            Environment.Exit(1)
        End If

        ' Parameter wird abgerufen
        Dim dbArticles As String = args(0)        ' la base de données

        ' Vorbereitung der Datenbankverbindung
        Dim articlesConn As OleDbConnection = Nothing        ' la connexion
        Dim myReader As OleDbDataReader = Nothing        ' le lecteur de données

        ' Zugriff auf die Datenbank wird versucht

        Try
            ' Verbindungszeichenfolge zur Datenbank
            Dim connectString As String = "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + dbArticles + ";"
            articlesConn = New OleDbConnection(connectString)
            articlesConn.Open()

            ' Ausführung eines Befehls SQL
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOleDbCommand As New OleDbCommand(sqlText)
            myOleDbCommand.Connection = articlesConn
            myReader = myOleDbCommand.ExecuteReader()

            ' Auswertung der abgerufenen Tabelle
            ' Anzeige der Spalten
            Dim ligne As String = ""
            Dim i As Integer
            For i = 0 To (myReader.FieldCount - 1) - 1
                ligne += myReader.GetName(i) + ","
            Next i
            ligne += myReader.GetName(i)
            Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))
            ' Anzeige der Daten
            While myReader.Read()
                ' Auswertung der aktuellen Zeile
                ligne = ""
                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i
                Console.WriteLine(ligne)
            End While
        Catch ex As Exception
            Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
            Environment.Exit(2)
        Finally
            ' Leser schließen
                myReader.Close()
                ' Verbindung schließen
                articlesConn.Close()
        End Try
        ' Ende
        Environment.Exit(0)
    End Sub
End Module

Die erzielten Ergebnisse:

dos>vbc liste.vb

E:\data\serge\MSNET\vb.net\adonet\6>dir
07/05/2002  15:09                2 325 liste.CS
07/05/2002  15:09                4 608 liste.exe
20/08/2001  11:54               86 016 ARTICLES.MDB

dos>liste articles.mdb

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

7.3.4. Aktualisierung einer Tabelle

In den vorangegangenen Beispielen wurde lediglich der Inhalt einer Tabelle aufgelistet. Wir passen unser Programm zur Verwaltung der Artikelstammdaten so an, dass es diese auch ändern kann. Das Programm heißt sql. Als Parameter wird ihm der Name DSN der zu verwaltenden Artikelstammdaten übergeben. Der Benutzer gibt die Befehle SQL direkt über die Tastatur ein, und das Programm führt sie aus, wie die folgenden Ergebnisse zeigen, die anhand der Artikelstammdatenbank MySQL erzielt wurden:

dos>vbc /r:microsoft.data.odbc.dll sql.vb

dos>sql mysql-articles

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

Requête SQL (fin pour arrêter) : select * from articles where stock_actuel<stock_minimum

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20

Requête SQL (fin pour arrêter) : insert into articles values ("1","1",1,1,1)
Il y a eu 1 ligne(s) modifiée(s)

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5
1 1 1 1 1

Requête SQL (fin pour arrêter) : update articles set nom="2" where nom="1"
Il y a eu 1 ligne(s) modifiée(s)

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5
1 2 1 1 1

Requête SQL (fin pour arrêter) : delete from articles where code="1"
Il y a eu 1 ligne(s) modifiée(s)

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

Requête SQL (fin pour arrêter) : select * from articles order by nom asc

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

c300 arc                            3500 10 20
f300 bouteilles d'oxygène           800 10 5
e300 combinaison de plongée         2800 34 7
d300 flèches - lot de 6             780 12 20
b300 pompe                          56 62 45
a300 vélo                           2500 10 5

Requête SQL (fin pour arrêter) : fin

Das Programm sieht wie folgt aus:


' Optionen
Option Explicit On 
Option Strict On

' Namensräume
Imports System
Imports System.Data
Imports Microsoft.Data.Odbc
Imports System.Data.OleDb
Imports System.Text.RegularExpressions
Imports System.Collections
Imports Microsoft.VisualBasic

Module db3
    Public Sub Main(ByVal args() As String)

        ' Konsolenanwendung
        ' führt über die Tastatur eingegebene Abfragen SQL auf einer 
        ' Tabelle ARTICLES einer Datenbank DSN, deren Name als Parameter übergeben wird
        Const syntaxe As String = "syntaxe : pg dsnArticles"

        ' Überprüfung der Parameter
        ' Gibt es 2 Parameter?
        If args.Length <> 1 Then
            ' Fehlermeldung
            Console.Error.WriteLine(syntaxe)
            ' Ende
            Environment.Exit(1)
        End If        'if
        ' Parameter wird abgerufen
        Dim dsnArticles As String = args(0)
        ' Verbindungszeichenfolge zur Datenbank
        Dim connectString As String = "DSN=" + dsnArticles + ";"

        ' Vorbereitung der Datenbankverbindung
        Dim articlesConn As OdbcConnection = Nothing
        Dim sqlCommand As OdbcCommand = Nothing
        Try
            ' Versuch, auf die Datenbank zuzugreifen
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()
            ' ein Befehlsobjekt wird erstellt
            sqlCommand = New OdbcCommand("", articlesConn)
            'try
        Catch ex As Exception
            ' Fehlermeldung
            Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
            ' Freigabe der Ressourcen
            Try
                articlesConn.Close()
            Catch
            End Try
            Environment.Exit(2)
        End Try        'catch
        ' Es wird ein Verzeichnis der akzeptierten SQL-Befehle erstellt
        Dim commandesSQL() As String = {"select", "insert", "update", "delete"}
        Dim dicoCommandes As New Hashtable
        Dim i As Integer
        For i = 0 To commandesSQL.Length - 1
            dicoCommandes.Add(commandesSQL(i), True)
        Next i

        ' Einlesen und Ausführen der über die Tastatur eingegebenen Befehle SQL
        Dim requête As String = Nothing        ' texte de la requête SQL
        Dim champs() As String        ' les champs de la requête    
        Dim modèle As New Regex("\s+")
        ' Schleife zum Eingeben und Ausführen der über die Tastatur eingegebenen Befehle SQL
        While True
            ' Zunächst keine Fehler
            Dim erreur As Boolean = False
            ' Abfrage der Anfrage
            Console.Out.Write(ControlChars.Lf + "Requête SQL (fin pour arrêter) : ")
            requête = Console.In.ReadLine().Trim().ToLower()
            ' Fertig?
            If requête = "fin" Then
                Exit While
            End If
            ' Die Abfrage wird in Felder zerlegt
            champs = modèle.Split(requête)
            ' Gültige Anfrage?
            If champs.Length = 0 Or Not dicoCommandes.ContainsKey(champs(0)) Then
                ' Fehlermeldung
                Console.Error.WriteLine("Requête invalide. Utilisez select, insert, update, delete")
                ' Nächste Abfrage
                erreur = True
            End If
            If Not erreur Then
                ' Vorbereitung des Command-Objekts zur Ausführung der Abfrage
                sqlCommand.CommandText = requête
                ' Ausführung der Anfrage
                Try
                    If champs(0) = "select" Then
                        executeSelect(sqlCommand)
                    Else
                        executeUpdate(sqlCommand)
                    End If
                Catch ex As Exception
                    ' Fehlermeldung
                    Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
                End Try
            End If
        End While
        ' Freigabe der Ressourcen
        Try
            articlesConn.Close()
        Catch
        End Try
        Environment.Exit(0)
    End Sub

    ' Ausführung einer Aktualisierungsanfrage
    Sub executeUpdate(ByVal sqlCommand As OdbcCommand)
        ' führt sqlCommand aus, Aktualisierungsabfrage
        Dim nbLignes As Integer = sqlCommand.ExecuteNonQuery()
        ' Anzeige
        Console.Out.WriteLine(("Il y a eu " & nbLignes & " ligne(s) modifiée(s)"))
    End Sub

    ' Ausführung einer Select-Abfrage
    Sub executeSelect(ByVal sqlCommand As OdbcCommand)
        ' führt sqlCommand aus, Select-Abfrage
        Dim myReader As OdbcDataReader = sqlCommand.ExecuteReader()
        ' Auswertung der abgerufenen Tabelle
        ' Anzeige der Spalten
        Dim ligne As String = ""
        Dim i As Integer
        For i = 0 To (myReader.FieldCount - 1) - 1
            ligne += myReader.GetName(i) + ","
        Next i
        ligne += myReader.GetName(i)
        Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))
        ' Anzeige der Daten
        While myReader.Read()
            ' Auswertung der aktuellen Zeile
            ligne = ""
            For i = 0 To myReader.FieldCount - 1
                ligne += myReader(i).ToString + " "
            Next i
            ' Anzeige
            Console.WriteLine(ligne)
        End While
        ' Freigabe der Ressourcen
        myReader.Close()
    End Sub
End Module

Wir gehen hier nur auf die Neuerungen gegenüber dem vorherigen Programm ein:

  • Wir erstellen ein Wörterbuch der akzeptierten SQL-Befehle:

        ' Es wird ein Verzeichnis der akzeptierten SQL-Befehle erstellt
        Dim commandesSQL() As String = {"select", "insert", "update", "delete"}
        Dim dicoCommandes As New Hashtable
        Dim i As Integer
        For i = 0 To commandesSQL.Length - 1
            dicoCommandes.Add(commandesSQL(i), True)
        Next i

Dadurch können wir anschließend ganz einfach überprüfen, ob das erste Wort (Feld [0]) der eingegebenen Abfrage einer der vier zulässigen Befehle ist:


            ' Gültige Abfrage?
            If champs.Length = 0 Or Not dicoCommandes.ContainsKey(champs(0)) Then
                ' Fehlermeldung
                Console.Error.WriteLine("Requête invalide. Utilisez select, insert, update, delete")
                ' Nächste Abfrage
                erreur = True
            End If            'if
  • Zuvor war die Abfrage mithilfe der Methode Split der Klasse RegEx in Felder zerlegt worden:

        Dim modèle As New Regex("\s+")
....
            ' Die Abfrage wird in Felder zerlegt
            champs = modèle.Split(requête)

Die Wörter, aus denen die Abfrage besteht, können durch beliebig viele Leerzeichen voneinander getrennt sein.

  • Die Ausführung einer Abfrage select erfolgt nicht nach dem gleichen Verfahren wie die einer Aktualisierungsabfrage (insert, update, delete). Daher muss ein Test durchgeführt und für jeden dieser beiden Fälle eine andere Funktion ausgeführt werden:

                ' Vorbereitung des Command-Objekts zur Ausführung der Abfrage
                sqlCommand.CommandText = requête
                ' Ausführung der Abfrage
                Try
                    If champs(0) = "select" Then
                        executeSelect(sqlCommand)
                    Else
                        executeUpdate(sqlCommand)
                    End If                    'try
                Catch ex As Exception
                    ' Fehlermeldung
                    Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
                End Try

Die Ausführung einer Abfrage SQL kann eine Ausnahme auslösen, die hier behandelt wird.

  • Die Funktion executeSelect greift alles auf, was in den vorherigen Beispielen behandelt wurde.
  • Die Funktion executeUpdate nutzt die Methode ExecuteNonQuery der Klasse OdbcCommand, die die Anzahl der vom Befehl betroffenen Zeilen zurückgibt.

7.3.5. IMPOTS

Wir greifen das in einem vorherigen Kapitel erstellte Objekt impôt wieder auf:


' Optionen
Option Strict On
Option Explicit On 

' Namensräume
Imports System

Public Class impôt
    ' die für die Steuerberechnung erforderlichen Daten
    ' stammen aus einer externen Quelle
    Private limites(), coeffR(), coeffN() As Decimal

    ' Hersteller
    Public Sub New(ByVal LIMITES() As Decimal, ByVal COEFFR() As Decimal, ByVal COEFFN() As Decimal)
        ' Es wird überprüft, ob alle drei Tabellen dieselbe Größe haben
        Dim OK As Boolean = LIMITES.Length = COEFFR.Length And LIMITES.Length = COEFFN.Length
        If Not OK Then
            Throw New Exception("Les 3 tableaux fournis n'ont pas la même taille(" & LIMITES.Length & "," & COEFFR.Length & "," & COEFFN.Length & ")")
        End If
        ' alles in Ordnung
        Me.limites = LIMITES
        Me.coeffR = COEFFR
        Me.coeffN = COEFFN
    End Sub

    ' Berechnung der Steuer
    Public Function calculer(ByVal marié As Boolean, ByVal nbEnfants As Integer, ByVal salaire As Integer) As Long
        ' Berechnung der Anzahl der Anteile
        Dim nbParts As Decimal
        If marié Then
            nbParts = CDec(nbEnfants) / 2 + 2
        Else
            nbParts = CDec(nbEnfants) / 2 + 1
        End If
        If nbEnfants >= 3 Then
            nbParts += 0.5D
        End If
        ' Berechnung des zu versteuernden Einkommens und des Familienquotienten
        Dim revenu As Decimal = 0.72D * salaire
        Dim QF As Decimal = revenu / nbParts
        ' Steuerberechnung
        limites((limites.Length - 1)) = QF + 1
        Dim i As Integer = 0
        While QF > limites(i)
            i += 1
        End While
        ' Ergebnisrückgabe
        Return CLng(revenu * coeffR(i) - nbParts * coeffN(i))
    End Function
End Class

Wir fügen ihm einen neuen Konstruktor hinzu, mit dem die Arrays limites, coeffR und coeffN aus einer Datenbank ODBC initialisiert werden können:


Imports System.Data
Imports Microsoft.Data.Odbc
Imports System.Collections
...


    ' Konstruktor 2
    Public Sub New(ByVal DSNimpots As String, ByVal Timpots As String, ByVal colLimites As String, ByVal colCoeffR As String, ByVal colCoeffN As String)
        ' Initialisiert die drei Grenzwerttabellen coeffR, coeffN anhand
        ' des Inhalts der Tabelle „Timpots“ aus der Datenbank ODBC DSNimpots
        ' colLimites, colCoeffR, colCoeffN sind die drei Spalten dieser Tabelle
        ' kann eine Ausnahme auslösen
        Dim connectString As String = "DSN=" + DSNimpots + ";"        ' chaîne de connexion à la base
        Dim impotsConn As OdbcConnection = Nothing        ' la connexion
        Dim sqlCommand As OdbcCommand = Nothing        ' la commande SQL
        ' die Abfrage SELECT
        Dim selectCommand As String = "select " + colLimites + "," + colCoeffR + "," + colCoeffN + " from " + Timpots
        ' Tabellen zum Abrufen der Daten
        Dim tLimites As New ArrayList
        Dim tCoeffR As New ArrayList
        Dim tCoeffN As New ArrayList

        ' Es wird versucht, auf die Datenbank zuzugreifen
        impotsConn = New OdbcConnection(connectString)
        impotsConn.Open()
        ' ein Befehlsobjekt wird erstellt
        sqlCommand = New OdbcCommand(selectCommand, impotsConn)
        ' Die Abfrage wird ausgeführt
        Dim myReader As OdbcDataReader = sqlCommand.ExecuteReader()
        ' Auswertung der abgerufenen Tabelle
        While myReader.Read()
            ' Die Daten der aktuellen Zeile werden in die Arrays übertragen
            tLimites.Add(myReader(colLimites))
            tCoeffR.Add(myReader(colCoeffR))
            tCoeffN.Add(myReader(colCoeffN))
        End While
        ' Freigabe der Ressourcen
        myReader.Close()
        impotsConn.Close()

        ' Die dynamischen Arrays werden in statische Arrays übertragen
        Me.limites = New Decimal(tLimites.Count) {}
        Me.coeffR = New Decimal(tLimites.Count) {}
        Me.coeffN = New Decimal(tLimites.Count) {}
        Dim i As Integer
        For i = 0 To tLimites.Count - 1
            limites(i) = Decimal.Parse(tLimites(i).ToString())
            coeffR(i) = Decimal.Parse(tCoeffR(i).ToString())
            coeffN(i) = Decimal.Parse(tCoeffN(i).ToString())
        Next i
    End Sub

Das Testprogramm läuft wie folgt ab: Es erhält als Argumente die Parameter, die an den Konstruktor der Klasse impôt übergeben werden sollen. Nach der Erstellung eines Objekts vom Typ impôt führt es Berechnungen zur zu zahlenden Steuer durch:


Option Explicit On 
Option Strict On

' Namensräume
Imports System
Imports Microsoft.VisualBasic

' Test-PG
Module testimpots
    Sub Main(ByVal arguments() As String)
        ' Interaktives Programm zur Steuerberechnung
        ' Der Benutzer gibt drei Daten über die Tastatur ein: verheiratet nbEnfants Gehalt
        ' Das Programm zeigt daraufhin die zu zahlende Steuer an
        Const syntaxe1 As String = "pg DSNimpots tabImpots colLimites colCoeffR colCoeffN"
        Const syntaxe2 As String = "syntaxe : marié nbEnfants salaire" + ControlChars.Lf + "marié : o pour marié, n pour non marié" + ControlChars.Lf + "nbEnfants : nombre d'enfants" + ControlChars.Lf + "salaire : salaire annuel en F"

        ' Überprüfung der Programmparameter
        If arguments.Length <> 5 Then
            ' Fehlermeldung
            Console.Error.WriteLine(syntaxe1)
            ' Ende
            Environment.Exit(1)
        End If        'if
        ' die Argumente werden abgerufen
        Dim DSNimpots As String = arguments(0)
        Dim tabImpots As String = arguments(1)
        Dim colLimites As String = arguments(2)
        Dim colCoeffR As String = arguments(3)
        Dim colCoeffN As String = arguments(4)

        ' Erstellung eines Steuerobjekts
        Dim objImpôt As impôt = Nothing
        Try
            objImpôt = New impôt(DSNimpots, tabImpots, colLimites, colCoeffR, colCoeffN)
        Catch ex As Exception
            Console.Error.WriteLine(("L'erreur suivante s'est produite : " + ex.Message))
            Environment.Exit(2)
        End Try

        ' Endlosschleife
        While True
            ' zunächst keine Fehler
            Dim erreur As Boolean = False

            ' die Parameter für die Steuerberechnung werden abgefragt
            Console.Out.Write("Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :")
            Dim paramètres As String = Console.In.ReadLine().Trim()

            ' Was ist zu tun?
            If paramètres Is Nothing Or paramètres = "" Then
                Exit While
            End If

            ' Überprüfung der Anzahl der Argumente in der eingegebenen Zeile
            Dim args As String() = paramètres.Split(Nothing)
            Dim nbParamètres As Integer = args.Length
            If nbParamètres <> 3 Then
                Console.Error.WriteLine(syntaxe2)
                erreur = True
            End If
            Dim marié As String
            Dim nbEnfants As Integer
            Dim salaire As Integer
            If Not erreur Then
                ' Überprüfung der Gültigkeit der Parameter
                ' verheiratet
                marié = args(0).ToLower()
                If marié <> "o" And marié <> "n" Then
                    Console.Error.WriteLine((syntaxe2 + ControlChars.Lf + "Argument marié incorrect : tapez o ou n"))
                    erreur = True
                End If
                ' nbEnfants
                nbEnfants = 0
                Try
                    nbEnfants = Integer.Parse(args(1))
                    If nbEnfants < 0 Then
                        Throw New Exception
                    End If
                Catch
                    Console.Error.WriteLine(syntaxe2 + "\nArgument nbEnfants incorrect : tapez un entier positif ou nul")
                    erreur = True
                End Try
                ' Gehalt
                salaire = 0
                Try
                    salaire = Integer.Parse(args(2))
                    If salaire < 0 Then
                        Throw New Exception
                    End If
                Catch
                    Console.Error.WriteLine(syntaxe2 + "\nArgument salaire incorrect : tapez un entier positif ou nul")
                    erreur = True
                End Try
            End If
            If Not erreur Then
                ' Die Parameter sind korrekt – die Steuer wird berechnet
                Console.Out.WriteLine(("impôt=" & objImpôt.calculer(marié = "o", nbEnfants, salaire).ToString + " F"))
            End If
        End While
    End Sub
End Module

Als Basis wird eine Datenbank mit dem Namen DSN mysql-impots verwendet:

C:\mysql\bin>mysql --database=impots --user=admimpots --password=mdpimpots
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5 to server version: 3.23.49-max-debug

Type 'help' for help.

mysql> show tables;
+------------------+
| Tables_in_impots |
+------------------+
| timpots          |
+------------------+

mysql> select * from timpots;
+---------+--------+---------+
| limites | coeffR | coeffN  |
+---------+--------+---------+
|   12620 |      0 |       0 |
|   13190 |   0.05 |     631 |
|   15640 |    0.1 |  1290.5 |
|   24740 |   0.15 |  2072.5 |
|   31810 |    0.2 |  3309.5 |
|   39970 |   0.25 |    4900 |
|   48360 |    0.3 |    6898 |
|   55790 |   0.35 |  9316.5 |
|   92970 |    0.4 |   12106 |
|  127860 |   0.45 |   16754 |
|  151250 |    0.5 | 23147.5 |
|  172040 |   0.55 |   30710 |
|  195000 |    0.6 |   39312 |
|       0 |   0.65 |   49062 |
+---------+--------+---------+

Die Ausführung des Testprogramms liefert folgende Ergebnisse:

dos>D:\data\devel\vbnet\poly\chap6\impots>vbc /r:system.data.dll /r:microsoft.data.odbc.dll /r:system.dll /t:library impots.vb

dos>vbc /r:impots.dll testimpots.vb

dos>test mysql-impots timpots limites coeffr coeffn
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :o 2 200000
impôt=22506 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :n 2 200000
impôt=33388 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :o 3 200000
impôt=16400 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :n 3 300000
impôt=50082 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :n 3 200000
impôt=22506 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :