Datenbanken in Delphi7/Kylix3

16/03/2011 - 18:19 von Matthias Hanft | Report spam
Hallo,

ich habe da ein sehr umfangreiches Projekt, das ich damals von vornherein
höchst betriebssystemunabhàngig geschrieben habe und das ich tatsàchlich
bis heute ohne Änderung (naja, ein paar gaaanz wenige "$IFDEF WIN32/LINUX"
gibts) sowohl unter Delphi 7 als auch Kylix 3 compilieren kann. Und das
soll auch so bleiben :-)

Jetzt kàme allerdings die Erfordernis dazu, eine kleine Datenbank dazu-
zubauen. Nichts großes, steht auch nie viel drin. Im Prinzip könnte man
das auch in selbergebaute Text- oder INI-Dateien o.à. schreiben (oder
natürlich ganz simpel ein File of Record), allerdings müßte man dann
halt die ganzen Speicher- und Suchalgorithmen etc. selber programmieren,
und wozu gibt es denn die ganzen schönen Datenbanken, wo man einfach
"SELECT irgendwas WHERE DINGS34" schreibt und das kriegt, was man
will.

Mitliefern wollte ich Firebird Embedded, das geht unter Windows auf
jeden Fall, und unter Linux wird es nicht "offiziell" unterstützt;
es gibt aber wenigstens eine "offizielle" "How-To"-Seite dafür.

Unter Delphi 7 verwende ich (mit einem Firebird 2.0 Server) i.d.R. die
mitgelieferte IBSQL-Komponente (jaja, weiß schon, überholt, buggy etc.,
aber bei mir tut die eigenartigerweise bis heute völlig problemlos),
aber bei Kylix gibts datenbankmàßig *nur* den "dbExpress"-Tab in der
IDE.

Also gut, dachte ich mir, den gibts in Delphi 7 ja auch, und da scheint
dann zwischen meinem EXE und GDS32.DLL einfach nur noch ein DBEXPINT.DLL
dazwischengeschaltet zu sein, was ich dann mit meiner Software auslie-
fern müßte. (Unter Linux ist es wohl àhnlich - habe ich noch nicht bis
ins letzte eruiert.)

Ich bin jetzt gerade dabei, die dbExpress-Sachen erst mal unter Windows
einzubauen. Im Prinzip geht das mit der TSQLConnection und der TSQLQuery
auch (inkl. Transactions); mißtrauisch wurde ich jetzt allerdings, als
die Parameterübergabe fehlschlug:

with SQLQueryInsert do begin
ParamByName('MANDANT').AsInteger:=1;
ParamByName('KUNDE').AsInteger:0;
ParamByName('RENR').AsString:='102011039001';
ParamByName('BIC').AsString:='TESTDEFFXXX';
ParamByName('IBAN').AsString:='DE99123456781234567890';
ParamByName('SEQTP').AsSmallInt:=0;
try
ExecSQL(True) // Direct=True, keine Ergebnismenge (Result=RowsAffected)
except
on E: Exception do
ShowMessage(E.Message)
end
end; (* with SQLQueryInsert *)

bringt Fehler 101: "SQL-Server-Fehler: Incorrect values within SQLDA structure".

Schreibt man die Parameter dagegen direkt in die SQL-Anweisung:

SQLQueryInsert.SQL.Clear;
SQLQueryInsert.SQL.Append('INSERT into TESTTABLE (MANDANT, KUNDE, RENR, BIC, IBAN, SEQTP)');
SQLQueryInsert.SQL.Append('values (1, 100, ''102011039001'',
''TESTDEFFXXX'', ''DE99123456781234567890'', 0);');
try
SQLQueryInsert.ExecSQL(True) // Direct=True, keine Ergebnismenge (Result=RowsAffected)
except
on E: Exception do
ShowMessage(E.Message)
end;

dann funktioniert's perfekt.

Nun könnte ich das natürlich so tun (auch bei SELECT-Abfragen), aber mittler-
weile beschleichen mich leise Zweifel, ob ich nicht doch ganz furchtbar auf
dem Holzweg bin, indem ich so alte und evtl. buggy Komponenten benutze (und
die "offiziell nicht unterstützte Firebird-Embedded-Installation" auf Linux
klingt auch nicht besonders einfach - unter Windows nimmt man halt Install-
shield oder sowas und fertig).

(Natürlich habe ich nach dieser SQLDA-Fehlermeldung gegooglet, aber außer
andere Leute mit dem gleichen Problem nichts weiter gefunden.)

Jetzt bin ich ein bißchen am Grübeln: Sollte ich...
a) ...den eingeschlagenen Weg weitermachen? Müßte dann halt alle SQL-
Queries ohne Parameter schreiben (wenn ich nicht noch herausbekomme, wo
die Flinte im Pfeffer... àh... der Hase im Korn... liegt), hàtte aber
ohne besondere Programmierung den großen Komfort eines SQL-Servers.
b) ...andere/aktuellere Komponenten verwenden? Da wird es aber schwer werden,
heutzutage noch etwas zu finden, das in Delphi 7 und Kylix 3 gleicher-
maßen funktioniert.
c) ...eine andere/moderne Datenbank (inkl. "Zubehör") nehmen? SQLite scheints
für Windows und Linux zu geben, sicher findet man da auch was für Delphi,
aber wie kommt man da von Kylix aus ran?! Irknwie libsqlite3.so aufrufen?
d) ...aufgeben und den "Datenbank-Teil" meines Projekts nur für Windows an-
bieten? (Da könnte ich mit meinem gewohnten, stabilen und robusten IBSQL
und FB-Embedded ja weitermachen.) Wàre aber schade, weil gerade die
"Zweisprachigkeit" (Windows/Linux) meiner Software schon was Besonderes
ist und ich davon nur ungern abrücken würde.
e) ...nur den Datenbankgedanken aufgeben und alles in ein File of Record
schreiben und dann eben selber suchen etc.? Ich kann noch nicht genau
abschàtzen, wie groß das alles wird, aber die Recordgröße seht Ihr oben
(ca. drei Integer, drei Strings, evtl. noch ein Timestamp o.à.), und die
Anzahl der Records nachher in Gebrauch wird vermutlich normalerweise in
der Größenordnung "ein paar hundert", maximal "ein paar tausend" liegen.
(Natürlich würde man das File of Records dann in eine eigene "Datenbank-
klasse" kapseln, wo es Methoden wie "GetRecordsByKunde(const aKunde: Integer)"
o.à. gàbe.) Das würde zwar anfangs etwas Schreibarbeit erfordern, aber
sicher zum gewünschten Ziel führen (und man hàtte jegliche Abhàngigkeit
von irgendwelchen Datenbanken, Treibern etc. eliminiert). Ich weiß halt
bloß nicht, wie schnell das geht, z.B. 1000 Records von einem TFileStream
einzulesen. Aber es liefe 100% identisch unter Windows und Linux (und die
$IFDEF beschrànken sich dabei höchstens noch auf das Verzeichnis: Hier
CSIDL_COMMON_APPDATA, dort /var/db o.à.).
Ok, man müßte das mit dem gleichzeitigen Zugriff regeln. Der kommt aber
im gegebenen Anwendungsfall i.d.R. eh nicht vor. Oder man schreibt in die
Bedienungsanleitung, daß man das Programm nur einmal gleichzeitig starten
darf :-)
f) oder gibts noch irgendwelche Möglichkeiten, an die ich gerade nicht denke?

Momentan tendiere ich am ehesten in Richtung e) (es muß auch mal fertig
werden, und bei allen anderen Varianten sehe ich immer noch mögliche
Unwàgbarkeiten auf mich zukommen). Auf jeden Fall schlafe ich da jetzt
erst nochmal drüber, bis ich mich endgültig entscheide (und Eure zahl-
reichen Antworten und Ratschlàge lese) :-)

Danke schon mal (auch fürs Durchlesen bis hier) :-)

Gruß Matthias.
 

Lesen sie die antworten

#1 Achim Kalwa
21/03/2011 - 19:06 | Warnen spam
Hallo,

Matthias Hanft wrote:

[...sehr viel...]

mißtrauisch wurde ich jetzt allerdings, als
die Parameterübergabe fehlschlug:

with SQLQueryInsert do begin
ParamByName('MANDANT').AsInteger:=1;
ParamByName('KUNDE').AsInteger:0;
ParamByName('RENR').AsString:='102011039001';
ParamByName('BIC').AsString:='TESTDEFFXXX';
ParamByName('IBAN').AsString:='DE99123456781234567890';
ParamByName('SEQTP').AsSmallInt:=0;
try
ExecSQL(True) // Direct=True, keine Ergebnismenge (Result=RowsAffected)



Da hast Du was falsch verstanden ;-)

ExecSQL(False);

wàre die korrekte Lösung.

ExecDirect zeigt an, dass die Query vor der Ausführung nicht vorbereitet
(prepared) werden muss. Dieser Wert kann auf True
gesetzt werden, wenn die Query keine anderen Parameter enthàlt.

HTH
Achim

Ähnliche fragen