Session D-MIX

Gemischtwarenladen: Techniken 
für daten(bank)unabhängige VFP-Programmierung

Andreas Flohr
INDISoftware GmbH


Einleitung

In der heutigen Zeit, die eine immer weitere Vernetzung der Computersysteme mit sich bringt, wird es auch immer wichtiger, auf neue und wechselnde Anforderungen zu reagieren. Auf die Daten einer Anwendung, die heute noch mit einer VFP-Datenbank arbeitet, soll plötzlich über das Internet zugegriffen werden, es soll auf eine anderes DBMS umgestellt werden usw., usw.

Immer häufiger müssen auch Daten in VFP-Anwendungen verarbeitet werden, die nicht, oder nur zum Teil im direkt zu verarbeitenden DBF-Format vorliegen, wie z.B.

·         SQL-Server Datenbankenwie Microsoft SQL-Server oder Oracle

·         PC-Datenbanken wie Access

Für diese Datenbanken gibt es die Möglichkeit, per Remoteview über ODBC-Treiber zuzugreifen. Dort müssen jedoch im Gegensatz zum Standard-Zugriff auf DBF einige Besonderheiten beachtet werden.

Was sieht es jedoch aus, wenn wir auf Daten aus z.B.

·         Standard-Anwendungen wie Excel oder Word

·         ASCII-Dateien und nicht zuletzt Internet und Webserver

zugreifen müssen. Sicherlich sind Ihnen die dann üblicherweise erforderlichen Im- und Exportroutinen bekannt, um auf diese Daten zuzugreifen. Sie schreiben speziell für jede Anwendung die benötigten Programme oder nutzen irgendwelche Tools, usw. usw.

Weiterhin ist immer mehr erforderlich, innerhalb einer Anwendung auf diverse, unterschiedliche Arten von Daten(banken) zuzugreifen bis hin zu einer Kombination von VFP-Daten / SQL-Serverdatenbank und WEB-Zugriff. Diese Anforderungen werden dann - wenn überhaupt möglich – individuell, mit sehr viel Aufwand für diese Anwendung realisiert, um dann bei der nächsten Erweiterung bzw. Änderung erneut mit viel Aufwand an die Anpassungen zu gehen.

Muss das immer so sein ??? .................. Nein!!!

Es ist erforderlich, im Bereich des Datenzugriffes einige neue Überlegungen anzustellen.

Das Konzept

Damit wir unsere Anwendungen unabhängig von den verwendeten Daten realisieren können, ist eine Trennung von der Benutzeroberfläche, der Geschäftslogik und dem Datenzugriff unbedingt erforderlich.

Wir besitzen mit Visual FoxPro ein Entwicklungssystem, welches uns durch seine Objektorientierung die Möglichkeiten bietet, eine universelle Datenzugriffsschicht zu realisieren, mit der wir unabhängig von der Art der Daten immer mit den gleichen Zugriffen innerhalb unserer Anwendungen arbeiten können.

Dazu realisieren wir eine Klassenbibliothek, in der sich die benötigten Klassen befinden. Dabei unterscheiden wir zwischen den Eigenschaften und Methoden, die wir unabhängig von den verwendeten Daten immer benötigen und den daten(bank)spezifischen Eigenschaften und Methoden, die sich speziell auf die verwendeten Daten beziehen. Zusätzlich wurde bei der Entwicklung dieser Klassenbibliothek auf folgende Punkte besonderer Wert gelegt:

·         Flexibilität: Die Informationen über die verwendeten Daten sollen möglichst von außen einstellbar sein. Dazu werden die Eigenschaften für die allgemeinen Datenzugriffsobjekte aus einer Ini-Datei eingelesen.

·         Kapselung: Alle Methoden und Eigenschaften der Kommandoklassen wurden so gekapselt, dass Sie von aussen ansprechbar sind und keine weiteren Objekte ausser der allgemeinen Datenzugriffsklasse benötigen.

·         Mehrfachinstanziierung: Die Klassen sind mehrinstanzfähig, d.h. Sie können mehrere Datenzugriffsklassen auf eine Form oder ein Applikationsobjekt ziehen.

·         Erweiterbarkeit: Das Konzept der Klassenbibliothek ist so ausgelegt das weitere Kommandoklassen für  neue Versionen von Datenbanken oder neue Techniken  wie z.B. ADO jederzeit ohne Probleme in die Klassenbibliothek eingefügt werden können.

Daraus ergibt sich nachfolgende Aufteilung der Klassen:

1.  Eine Klasse zum Lesen und Schreiben von INI-Dateien (ini)

Wir erstellen uns eine Basisklasse, welche alle Eigenschaften und Methoden besitzt um aus einer beliebigen INI-Datei Eintragungen Lesen und Schreiben zu können. Das sind im Einzelnen:

·    Eine Eigenschaft für den Namen und den Pfad der INI-Datei.

·    Allgemeine Methoden zum Lesen und Schreiben aus einer INI-Datei über Windows-Api Funktionen

·    Eine Spezielle Methode zum Lesen der Spezifischen Einträge für das Allgemeine Datenzugriffsobjekt.

Dabei wird für jedes allgemeine Datenzugriffsobjekt eine eigene Section angelegrt, die der Name-Eigenschaft des allgemeinen Datenzugriffsobjektes entspricht. Somit können unterschiedliche Datenkonfigurationen in einer INI-Datei abgelegt werden.

2.    Eine allgemeine Datenzugriffsklasse (data)

Wir erstellen eine allgemeine Datenzugriffsklasse, welches alle allgemeinen Eigenschaften und Methoden, unabhängig von der verwendeten Art der Daten, beinhaltet. Diese Klasse enthält grundlegende Eigenschaften und Informationen über die zu verwendenden Daten, wie z.B. cPathDatabase, cDatabaseTyp, cDataBaseName und Methoden zum:

·         Öffnen von Datenbanken

·         Öffnen und Schliessen von Daten oder Dateien

·         Öffnen und Schliessen von Verbindungen

3.   Eine Basis - Kommandoklasse für Daten (datacmd)

Für den Zugriff auf die verwendeten Daten erstellen wir uns eine Basis Kommandoklasse für Daten, die alle, für den Zugriff auf die jeweiligen Daten, benötigten Methoden enthält. Dazu überlegen wir uns, welche Zugriffe für alle Arten von Daten erforderlich sind. Wir benötigen innerhalb unserer Anwendungen allgemeine Methoden zum:

·         Selektieren und Suchen  von Daten

·         Neuanlegen, Ändern und Löschen von Daten

·         Konvertieren von Datentypen

·         Navigieren innerhalb der Daten

Diese Basis - Kommandoklasse für Daten enthält in Ihren Methoden den Code für den Zugriff auf VFP-Datenbanken und Tabellen. Alle weiteren Kommandoklassen für weitere Arten von Daten werden von dieser Basis-Kommandoklasse abgeleitet. Alle Kommandoklassen für Daten besitzen damit den gleichen Satz von Wrapper-Methoden für die Arbeit mit Daten, d.h.

·         Sie greifen nur noch über die Wrapper-Methoden auf die Daten der Anwendung zu.

·         Unabhängig von der Art der Daten benutzen Sie immer die gleichen Methoden mit den identischen Aufrufen.

·         Die Kommandoklasse sorgt dafür, das die für diese Art von Daten richtigen Zugriffe ausgeführt werden.

Die Klassen

Nachfolgend werden die wichtigsten Eigenschaften und Methoden der allgemeinen Datenzugriffsklasse aufgelistet:

·        Allgemeine Datenzugriffsklasse (data):

Eigenschaft

Beschreibung

cconnectionname

Gibt den Namen einer Verbindung an, die mit CREATE CONNECTION erstellt wurde. Wird aus der INI-Datei gelesen (Connectionname). Wenn in der INI-Datei nichts steht, wird der Defaultwert: leer gesetzt, falls kein Wert eingetragen wurde.

cconnectionstring

Enthält einen Connectionstring, wie z.B. 'dsn=MyFoxSQLNT;uid=sa;pwd=FOXPRO'. Wird aus der INI-Datei gelesen (Connectionstring). Wenn in der INI-Datei nichts steht, wird der Defaultwert: leer gesetzt, falls kein Wert eingetragen wurde.

cdatabase

Enthält den Datenbanknamen. Wird aus der INI-Datei gelesen (DatabaseName). Wenn in der INI-Datei nichts steht, wird der Defaultwert: leer gesetzt, falls kein Wert eingetragen wurde.

cdatabasetype

Enthält den verwendeten Datenbanktyp Wird aus der INI-Datei gelesen (DatabaseType). Wenn in der INI-Datei nichts steht, wird der Defaultwert: VFP gesetzt, falls kein Wert eingetragen wurde.

cdatasourcename

Enthält den Namen der DataSource. Wird aus der INI-Datei gelesen (DataSourceName). Wenn in der INI-Datei nichts steht, wird der Defaultwert: leer gesetzt, falls kein Wert eingetragen wurde.

cpassword

Enthält das Passwort für die VERBINDUNG zur SQL-DB. Wird aus der INI-Datei gelesen (Password). Wenn in der INI-Datei nichts steht, wird der Defaultwert: leer gesetzt, falls kein Wert eingetragen wurde.

cpathdatabase

Enthält den Pfad der Datenbank. Wird aus der INI-Datei gelesen (PathData). Wenn in der INI-Datei nichts steht, wird der Defaultwert: TABELLEN gesetzt, falls kein Wert eingetragen wurde.

cremotedatabase

Enthält den Datenbanknamen für die VERBINDUNG zur SQL-DB. Wird aus der INI-Datei gelesen (RemoteDataBase). Wenn in der INI-Datei nichts steht, wird der Defaultwert: leer gesetzt, falls kein Wert eingetragen wurde.

cuserid

Enthält den usernamen für die VERBINDUNG zur SQL-DB. Wird aus der INI-Datei gelesen (Username). Wenn in der INI-Datei nichts steht, wird der Defaultwert: leer gesetzt, falls kein Wert eingetragen wurde.

lnetzwerk

Bei .T. wird ein DBC-Container Shared für alle, sowie für jeden User ein exkl. lokaler DBC (mit LOCAL im Namen). erzeugt. Bei Remote-DB immer .F. DEFAULT = .F.

lreadmemo

Nur für REMOTE-VIEWS (Eigenschaft FetchMemo): Environmenteinstellung siehe Hilfe. DEFAULT: .F.

lshareconnection

Legt fest, ob Remote-Views eine Verbindung gemeinsam nutzen sollen. DEFAULT: .F.

lTalk

Diese Eigenschaft legt fest, ob während des Abrufes von Daten eine Fortschrittsanzeige angezeigt werden soll. (.T.=DEFAULT) oder nicht (.F.). Die SET TALK Einstellung wird gesetzt.


Eigenschaft

Beschreibung

nconnectionhandle

Enthält den Handle der Connection, einen numerischen Wert # 0. (Default= 0)

nreaddata

Nur für REMOTE-VIEWS (Eigenschaft Fetchsize): Legt fest, wieviele Sätze auf einmal gelesen werden. -1(alle). 0 (keine), n (Anzahl Sätze) DEFAULT: 100

viewbuffering

LOCAL und REMOTE-VIEWS (Eigenschaft Buffering) Environmenteinstellung siehe Hilfe. DEFAULT = 3

viewupdatetype

LOCAL und REMOTE-VIEWS (Eigenschaft UpdateType) Environmenteinstellung siehe Hilfe. DEFAULT = 1

viewwheretype

LOCAL und REMOTE-VIEWS (Eigenschaft WhereType) Environmenteinstellung 


Methode

Beschreibung

addocmd

Fügt dem SQL-Objekt in Abhängigkeit der Eigenschaft cDatabaseType das zugehörige CMD-Objekt hinzu

closeconnection

Schließt die Verbindun

closetable

Schließt eine geöffnete Tabelle, wenn es sich um eine VFP-Datenbank handelt. Bei SQL-DB keine Funktion. 

createconnection

Baut eine Connection auf, oder ändert eine bestehende Connection im aktuellen DBC.

getconnectionhandle

Ermittelt den aktuellen ConnectionHandle. RETURN(nHandle)

openconnectio

Öffnet eine Connection zu einer SQL-Datenbank

opentable

Öffnet eine Tabelle, wenn es sich um eine VFP-Datenbank handelt. PARAMETER: RETURN: .T. when die Tabelle geöffnet wurde,.F. wenn die Tabelle bereits offen war, oder nicht geöffnet werden mußte.

setcursorenvdefaults

Setzt die Umgebungseinstellungen aus den Eigenschaften ViewUpdateType, ViewWhereType, ViewBuffering, lReadMemo, nReaddata für alle Views.

setdatabase

Öffnet die Datenbank, die in cDatabase eingetragen ist und setzt die Standardeinstellungen. Kann in der Anwendungsspezifischen SQL-Klasse überschrieben werden.

setindex

Prüft, ob ein Index für das übergebene Feld bereits existiert. Wenn nicht, wird ein Index erzeugt, sonst nur auf diesen gewechselt. 

sqlappendcondition

Diese Methode prüft einen übergebenen SQL-String auf das Vorhandesein einer Bedingung (optional), und fügt diese korrekt ein, wenn die Bedingung nicht vorhanden ist. RETURN: der neue SQLstring

sqlcreatecondition

Diese Methode erstellt eine Bedingung für einen SQLString. RETURN: Die erzeugte Bedingung oder ein Leerstring.

Vfpcreatecondition

Diese Methode erstellt eine Bedingung für einen VFP-Befehl (z.B. SET FILTER TO) RETURN: Die erzeugte Bedingung oder ein Leerstring.


·         Die Basis - Kommandoklasse für Daten (datacmd)

Nachfolgend werden die wichtigsten Methoden der Basis-Kommandoklasse für Daten aufgelistet:

Methode

Beschreibung

Converttosql
Wandelt den Wert eines beliebigen Datentyps in einen String in Hochkomma um . Wird bei Erstellung von programmatischen SQL-Befehlen benötigt. RETURN: Wert als String, bei D,M,T,C in Hochkomma.
Converttostring
Wandelt den Wert eines beliebigen Datentyps in einen String um . RETURN: Wert als String.
Datacommitchanges
Speichert die Änderungen endgültig in der Datenbank ab. RETURN: DATA_OK, DATA_REST, DATA_ERROR, INTERNAL_ERROR
Datacount
Ermittelt die Anzahl der Datensätze einer Tabelle/View. RETURN: Anzahl der Sätze
Datacreateview
Erstellt einen programmatischen View in einer Datenbank (DBC).
Datadelete
Diese Methode führt ein DELETE-SQL (VFP oder SPT) Kommando aus. RETURN: DATA_OK, DATA_REST, DATA_ERROR, INTERNAL_ ERROR
Datainsert
Diese Methode führt ein INSERT-SQL (VFP oder SPT) Kommando aus. RETURN: DATA_OK, DATA_REST, DATA_ERROR, INTERNAL_ ERROR
Datalookup
Ersatz für VFP-LOOKUP Funktion. RETURN: Gefundener Wert oder Leerwert des gleichen Datentypes.
Datanewid
Erzeugt den nächsten eindeutigen Schlüssel für die übergebene Tabelle. RETURN: Nächste Freie eindeutige ID.
Datarequery
Fragt die Daten erneut ab, z.B. bei einem View mit REQUERY(). Ermittelt immer die Anzahl der Sätze. RETURN: .<0-n> --> Anzahl der Datensätze, .-1 --> Fehler aufgetreten
Dataselect
Diese Methode führt ein SELECT-SQL (VFP oder SPT) Kommando aus. RETURN: Anzahl der gefundenen Sätze.
Dataupdate
Diese Methode führt ein UPDATE-SQL (VFP oder SPT) Kommando aus.
 

·         Die Basisklasse für die INI-datei (ini):

Eigenschaft/Methode

Beschreibung

CIniFileName
Enthält den Namen des INI-Files der Anwendung
GetIniFilename
Ermittelt den Namen der Ini.Datei. (<Anwendungsname>.ini)
GetInistring
Liest einen Wert aus einer INI-Datei. PARAMETER: <SectionName>,<Variable>,[<lNoMessage>] Default = Fehler anzeigen
GetDataIniStrings
In dieser Methode werden beim Initialisieren eines Allgemeinen Datenzugriffsobjektes die Datenangaben aus der Ini-Datei gelesen und eingestellt.
WriteiniString
Schreibt einen Wert in die Ini-Datei. PARAMETER:<SectionName>,<VariablenName>,<Wert>

Die Implementierung

Beim Starten der Anwendung wird zuerst das Objekt der INI-Klasse instanziiert (oIni). Dies ist möglich über einen Aufruf in der verwendeten Applikationsklasse, z.B.

    oApp.Addobject(„oIni“,“ini“)

oder einen Aufruf im Hauptprogramm der Anwendung, z.B.

    oIni = NEWOBJECT(„Ini“,“mixdata.vcx“).

Dieses Objekt holt sich den Dateinamen der verwendeten INI-Datei in der Methode GetIniFilename() und legt Ihn in der Eigenschaft cIniFileName ab.

Danach wird ein erstes allgemeines Datenzugriffsobjekt instanziiert, welches wiederum in einer verwendeten Applikationsklasse oder im Hauptprogramm durchgeführt wird. In der Init()-Methode dieser Klasse wird dann zuerst über die Methode

    (oApp.)oIni.GetDataIniStrings()

auf die INI-Datei zugegriffen, um evtl. vorhandene Einträge zu lesen. Dabei wird die Objektreferenz des allgemeinen Datenzugriffsobjektes übergeben, um auf die richtige Section in der INI-Datei zuzugreifen.

Es sindfolgende Eintragen in der INI-Datei möglich:

INI-Datei Eintrag

Eigenschaftsname in Klasse data

DatabaseName
cdataBase
DatabaseType
cDataBaseType
ConnectionName
cConnectionName
ConnectionString
cConnectionString
DataSourceName
cDataSourceName
Password
cPassword
UserID
cUserID
RemoteDatabase
cRemoteDataBase

 

Dabei gelten folgende Regeln: Ein eingetragener Wert in der Ini-Datei hat immer die höchste Priorität, d.h. er übersteuert alle bereits eingegebenen Werte der Eigenschaften. Der Default-Wert für eine Eigenschaft wird erstdann gesetzt, wenn kein anderer Wert in dieser Eigenschaft steht UND in der INI-Datei kein Wert angegeben wurde.

 

    Nachfolgend der Code der Methode GetDataIniStrings():

      LPARAMETERS toobj
      LOCAL lcIniValue
      IF TYPE("toObj") # "O" OR ISNULL(toObj)
         RETURN
      ENDIF
      WITH toObj   
         *-- Lesen des Datenbanknamens aus der Ini-Datei.
         lcIniValue = this.GetIniString(.Name,'DatabaseName',.T.)
         *-- Wenn kein Datenbankname gefunden wird, nehmen wir Default = leer
         IF EMPTY(lcIniValue)
           IF .cDatabase = '['
               .cDatabase = ''
           ENDIF   
         ELSE
      .cDatabase = lcIniValue
      ENDIF
      *-- Lesen des Databasetype aus der Ini-datei
      lcIniValue = this.GetIniString(.Name,'DatabaseType',.T.)
         *-- Wenn kein Datenbanktyp gefunden wird, nehmen wir Default = VFP
      IF EMPTY(lcIniValue)
      IF .cDatabaseType = '['
      .cDatabaseType = "VFP"
      ENDIF
      ELSE
      .cDatabaseType = UPPER(ALLTRIM(lcIniValue))
      ENDIF
      *-- Wir haben eine SQL-Datenbank
    IF .cDatabasetype # "VFP"
    *-- Lesen des Verbindungsnamens aus der Ini-Datei.
    lcIniValue = this.GetIniString(.Name,'ConnectionName',.T.)
      IF EMPTY(lcIniValue)
    *-- Falls kein Wert gefunden wird, nehmen wir Default = leer
    IF .cConnectionname = '['
           .cConnectionname = ''
          ENDIF
      ELSE
    .cConnectionname = lcIniValue
      ENDIF
       *-- Lesen des VerbindungsStrings aus der Ini-Datei.
    lcIniValue = this.GetIniString(.Name,'ConnectionString',.T.)
       IF EMPTY(lcIniValue)
    *-- Falls kein Wert gefunden wird, nehmen wir Default = leer
    IF .cConnectionString = '['
           .cConnectionString = ''
          ENDIF
      ELSE
         .cConnectionString = lcIniValue
       ENDIF
       *-- Lesen des DataSourceNamens aus der Ini-Datei.
       lcIniValue = this.GetIniString(.Name,'DataSourceName',.T.)
       IF EMPTY(lcIniValue)
    *-- Falls kein Wert gefunden wird, nehmen wir Default = leer
    IF .cDataSourceName = '['
            .cDataSourceName = ''
          ENDIF
      ELSE
    .cDataSourceName = lcIniValue
       ENDIF
       *-- Lesen des Kennwortes aus der Ini-Datei.
    lcIniValue = this.GetIniString(.Name,'Password',.T.)
       IF EMPTY(lcIniValue)
    *-- Falls kein Wert gefunden wird, nehmen wir Default = leer
    IF .cPassword = '['
    .cPassword = ''
          ENDIF
      ELSE
    .cPassword = lcIniValue
       ENDIF
      *-- Lesen des Usernamens aus der Ini-Datei.
    lcIniValue = this.GetIniString(.Name,'Userid',.T.)
       IF EMPTY(lcIniValue)
    *-- Falls kein Wert gefunden wird, nehmen wir Default = leer
    IF .cUserid = '['
            .cUserid = ''
          ENDIF
       ELSE
    .cUserid = lcIniValue
       ENDIF
       *-- Lesen der Remote-Datenbank aus der Ini-Datei.
    lcIniValue = this.GetIniString(.Name,'RemoteDataBase',.T.)
      IF EMPTY(lcIniValue)
    *-- Falls kein Wert gefunden wird, nehmen wir Default = leer
    IF .cRemoteDatabase = '['
             .cRemoteDatabase = ''
          ENDIF
       ELSE
         .cRemoteDatabase = lcIniValue
       ENDIF
       ENDIF
    ENDWITH

Nachdem die Eigenschaften des Allgemeinen Datenzugriffsobjektes gefüllt worden sind, wird als nächstes das zu verwendende Kommandoobjekt instanziiert. Dabei wird das Kommandoobjekt immer mit der Objektreferenz oCMD an das aufrufende Datenzugriffsobjekt angehängt.Dies geschieht über den Aufruf der Methode

  this.AddoCmd()

    Nachfolgend der Code der Methode addoCMD():

    LOCAL lcDBTyp
    lcDBTyp = UPPER(ALLTRIM(this.cDatabaseType))
    DO CASE
      CASE lcDBTyp = "ASCII"
      this.Addobject('oCMD','dataCMDascii')
       CASE lcDBTyp = "HTTP"
         this.Addobject('oCMD','dataCMDhttp'
      CASE lcDBTyp = "VFP"
      this.Addobject('oCMD','dataCMD')
       CASE lcDBTyp = "ORACLE7"
      this.Addobject('oCMD','dataCMDora7')
      CASE lcDBTyp = "ORACLE8"
     this.Addobject('oCMD','dataCMDora8')
      CASE lcDBTyp = "MSSQL6"
      this.Addobject('oCMD','dataCMDSql6')
       CASE lcDBTyp = "MSSQL7"
    this.Addobject('oCMD','dataCMDSql7')
      CASE lcDBTyp = "ODBCVFP"
      this.Addobject('oCMD','dataCMDOBDCVFP')
    OTHERWISE
            *-- Eine Verbindung zu einer anderen ODBC-Datenquelle
            *-- Dies kann auch Access oder eine andere PC-Datenbank sein,
            *-- welche über einen ODBC-Treiber erreicht werden kann.
    this.Addobject('oCMD','cusSQLCMDODBC')
    ENDCASE
    IF TYPE('this.oCMD') # 'O' OR ISNULL(this.oCMD)
    RETURN .F.
    ENDIF

Damit ist die Initialisierung der Datenzugriffschicht abgeschlossen. Nehmen wir an , das es sich um einen Datenzugriff auf einen VFP-Datenbankcontainer handelt und wir das allgemeine Datenzugriffsobjekt oVfp (Eigenschaft Name = „oVFP“) genannt haben, so können wir jetzt jederzeit in unserer Anwendung über die Objektreferenz

oVFP.oCMD.<Eigenschaft oder Methodenname>

auf unser Kommandoobjekt für die VFP-Datenbank zugreifen.

Mit der gleichen Technik lassen sich jetzt beliebig viele weitere Datenzugriffsobjekt instanziieren. dabei ist es völlig egal, ob Sie diese als Globale Objekt erzeugen (oSQL.oCMD) oder an ein Applikationsobjekt hängen (oApp.oSQL.oCMD) oder sogar nur innerhalb einer Form verwenden (thisform.oSQL.oCMD)! Entscheiden Sie das daran, wo Sie eine Funktionalität innerhalb Ihrer Anwendung benötigen. Alle Methoden der Kommandoklasse sind so gekapselt, das Sie ausser der Obejktreferenz oCMD keine anderen festgelegten Objekthierachien benötigen !

 

Das Ergebnis

Als Ergebnis unserer Überlegungen sehen wir in der nachfolgenden Abbbildung die realisierte Klassenbibliothek.

    Abb. 1: Die Klassenbibliothek mixdata.vcx

 

Anzumerken waäre hier noch, dass wir unterhalb der Basiskommandoklasse datacmd eine weitere Klasse datacmdodbc eingefügt haben, die den Standardcode in Ihren Methoden für einen Zugriff über ODBC-Treiber auf Datenbanken enthält. Alle speziellen Kommandoklassen für die darüber angesprochenen Datenbanken sind wiederum von dieser Klasse abgeleitet. Damit ist es innerhalb der davon abgeleiteten Kommandoklasse, wie z.B. für den Microsoft SQL-Server, nur noch erforderlich, den speziellen Code für dieses Datenbanksystems einzutragen.

Zusammenfassung

Die hier besprochende Datenzugriffsschicht enthält sämtliche Grundfunktionalität für den Zugriff auf Daten. Sie ist problemlos um zusätzliche Funktionalitäten erweiterbar, wie z.B.

    ·         zentrale Fehlerbehandlung

    ·         Transaktionssteuerung

    ·         Prüfen von Aktualisierungskonflikten

Überlegen Sie bei Erweiterungen immer nur, ob es sich um eine Allgemeine Funktionalität handelt, die für alle Datenzugriffe gleich durchzuführen ist, dann gehört diese Funktionalität in die Allgemeine Datenzugriffsklasse. Ist eine Erweiterung aber spezifisch für die Art der verwendeten Daten, muß Sie in der Basiskommandoklasse eingefügt und in der jeweiligen spezifischen Kommandoklasse ausprogrammiert werden.

Für weitere Fragen stehe ich Ihnen jederzeit unter Flohr@indisoftware.de oder auf unserem Stand auf der Konferenz zur Verfügung.

Sie erreichen mich auch im dFPUG-Forum unter www.dfpug.de/forum oder auf unserer Website www.indisoftware.de.