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.
Es ist erforderlich, im Bereich des Datenzugriffes einige neue Überlegungen anzustellen.
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:
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.
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
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.
Nachfolgend werden die wichtigsten Eigenschaften und
Methoden der allgemeinen Datenzugriffsklasse aufgelistet:
· Allgemeine
Datenzugriffsklasse (data):
Eigenschaft Beschreibung 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.
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. 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.
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. 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. 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. 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. 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.
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.
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. Nur für REMOTE-VIEWS (Eigenschaft FetchMemo):
Environmenteinstellung siehe Hilfe. DEFAULT: .F. Legt fest, ob Remote-Views
eine Verbindung gemeinsam nutzen sollen. DEFAULT: .F. 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 Enthält den Handle der Connection, einen
numerischen Wert # 0. (Default= 0) 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 LOCAL und REMOTE-VIEWS (Eigenschaft Buffering)
Environmenteinstellung siehe Hilfe. DEFAULT = 3 LOCAL und REMOTE-VIEWS (Eigenschaft UpdateType)
Environmenteinstellung siehe Hilfe. DEFAULT = 1 LOCAL und REMOTE-VIEWS (Eigenschaft WhereType)
Environmenteinstellung Methode
Beschreibung Fügt dem SQL-Objekt in Abhängigkeit der
Eigenschaft cDatabaseType das zugehörige CMD-Objekt hinzu Schließt
die Verbindun Schließt eine geöffnete
Tabelle, wenn es sich um eine VFP-Datenbank handelt. Bei SQL-DB keine
Funktion. Baut eine Connection auf, oder ändert eine
bestehende Connection im aktuellen DBC. Ermittelt den aktuellen ConnectionHandle. RETURN(nHandle)
Öffnet eine Connection zu einer SQL-Datenbank
Ö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. Setzt die Umgebungseinstellungen aus den Eigenschaften
ViewUpdateType, ViewWhereType, ViewBuffering, lReadMemo, nReaddata
für alle Views. Öffnet die Datenbank, die in cDatabase eingetragen
ist und setzt die Standardeinstellungen.
Kann in der Anwendungsspezifischen SQL-Klasse überschrieben werden.
Prüft, ob ein Index für das übergebene
Feld bereits existiert. Wenn nicht, wird ein Index erzeugt, sonst
nur auf diesen gewechselt. 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 Diese Methode erstellt eine Bedingung für
einen SQLString. RETURN: Die erzeugte Bedingung oder ein Leerstring.
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
· Die
Basisklasse für die INI-datei (ini):
Eigenschaft/Methode
Beschreibung
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.
oder einen Aufruf im Hauptprogramm der Anwendung,
z.B.
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
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:
Eigenschaftsname
in Klasse data
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():
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 Nachfolgend der Code der Methode addoCMD(): 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 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
! 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.
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.1. Eine Klasse zum Lesen und Schreiben von INI-Dateien
(ini)
2. Eine allgemeine Datenzugriffsklasse (data)
3. Eine Basis - Kommandoklasse für Daten (datacmd)
Die Klassen
cconnectionname
cconnectionstring
cdatabase
cdatabasetype
cdatasourcename
cpassword
cpathdatabase
cremotedatabase
cuserid
lnetzwerk
lreadmemo
lshareconnection
lTalk
nconnectionhandle
nreaddata
viewbuffering
viewupdatetype
viewwheretype
addocmd
closeconnection
closetable
createconnection
getconnectionhandle
openconnectio
opentable
setcursorenvdefaults
setdatabase
setindex
sqlappendcondition
sqlcreatecondition
Vfpcreatecondition
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.
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
oApp.Addobject(„oIni“,“ini“)
oIni = NEWOBJECT(„Ini“,“mixdata.vcx“).
(oApp.)oIni.GetDataIniStrings()
INI-Datei
Eintrag
DatabaseName
cdataBase
DatabaseType
cDataBaseType
ConnectionName
cConnectionName
ConnectionString
cConnectionString
DataSourceName
cDataSourceName
Password
cPassword
UserID
cUserID
RemoteDatabase
cRemoteDataBase
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
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
Das Ergebnis
Zusammenfassung