Einzelnen Beitrag anzeigen

cytrinox

Registriert seit: 4. Sep 2006
88 Beiträge
 
#1

Crystal Reports XI + Delphi und unterschiedliche Datenbanken

  Alt 4. Aug 2007, 15:33
Datenbank: alle von Zeos untersützten DB • Zugriff über: Zeos
Hi,

ich hab ein recht kompliziertes Problem mit Crystal Reports und Delphi.

Wir haben eine recht große Applikation in Delphi (Win32) die intern die Zeos Komponenten benutzt. Sinn der Sache ist der, dass man momentan nur eine embedded Firebird Datenbank einbindet (für Einzeplplatz-Versionen) oder einen Firebird-Server (für Netzwerk-Versionen mit mehreren Clients). Später sollen dann MSSQL und Oracle dazukommen. D.h. Die Application ist so ausgelegt, dass man im Prinzip jede Datenbank, die Zeos untersüttzt, auch anbinden kann.

Im Programm drin gibt es ein Benutzersystem, hunderten von Zugriffsrechen usw. auf bestimmte Teile des Programms und damit auch auf die Datenbestände/Tabellen an sich.


Jetzt sollen mit Crystal Reports diese Daten ausgewertet werden. Das sind ca. 200 Auswertungen und Statistiken, die ich schon alle erstellt und die auch schon mit dem Programm zusammen ausgeliefert werden.

Dazu hab ich die Delphi Komponente für CRXI verwendet, da gibts TCrpe und TCrpeDS.

Und zwar hat man bei CR ja die Möglichkeit, über integrierte Treiber oder über ODBC, JDBC usw. eine Datenbank anzubinden. D.h. Crystal kann in dem Fall direkt mit der verbunden Datenbank über SQL kommunizieren.

In meinem Fall hab ich ja aber keine Ahnung welche Datenbank angebunden ist, zumal noch die Zugriffsgeschichte reinfällt.

D.h. ich hab für jede Tabelle ein *.ttx File angelegt, das die Feldgröße, Feldname usw. beinhaltet. Diese Dateien kann man als eine Felddefinitionsdatei in einen Report laden und kann damit auch einen kompletten Report erstellen.
Erst wenn der Report in einem Programm per TCrpe Komponente geladen wird, wird dynamisch die Datenquelle zugewiesen.

Dazu stellt die Crpe Komponente alle Tabellen, die in dem Report vorkommen, zu Verfügung, dann kann man einfach ein vorhandenes TDataSet damit per DataPointer damit verbinden.

Also hab ich z.B. eine Tabelle MY_DATA in dem Report defniert, muss ich zuerst eine ZQuery erstellen, ein "SELECT * FROM MY_DATA"; ausführen und das daraus resultierende Dataset in ein TCrpeDS Object packen. Dieses repräsentiert sozusagen die Datenquelle für den Report und diese kann ich nun der Tabelle die mir TCrpe ausgibt, zuweisen (tableByName('MY_DATA').DataPointer := myTcrpeDSobj).

Somit ist es für mich beim Report-Erstellen und auswerten völlig schnurz, welches DBMS dahinter steht, die Applikation gibt mir ja immer das passende Dataset zurück.

Manchen wird es schon aufgefallen sein: Wenn ich einen Report erstellen muss, der zwei Tabellen braucht die per INNER JOIN z.B. verknüpft werden bedeutet das in meinem Fall, dass ich zuerst ein SELECT * FROM tbl1 mache und das Dataset zuweise, dann ein SELECT * FROM tbl2 mache und das Dataset wiederum zuweise.

Crystal macht jetzt den INNER JOIN selbst aus den zwei Datasets die es bekommt. Bei 100000 x 10000 Datensätzen dauert das eine halbe Ewigkeit.
Das Problem liegt daran, dass Crystal - wenn es eine SQL fähige Datenbank hat - direkt einen SQL INNER JOIN Befehl zusammenbaut und den an die Datenbank schickt. Genau DAS ist hier nicht der Fall - es geht technisch einfach nicht.

Und genau hier muss ich jetzt ansetzen...

Es wird langsam untragbar, das eine Auswertung, die über SQL eigentlich 2-3 Sekunden braucht, bei unseren Kunden oft über 15-30 Minuten dauert.


Da ich nicht nur richtige Server anbinden muss, sondern auch eine embedded Firebird Datenbank habe, die schon durch das Programm geöffnet ist, fällt ein direkter Zugriff von CRXI auf die Datenbank weg - ganz zu schweigen von den ganzen Zugriffsrechen usw.

Ein Zugriff über diese *.ttx Files ist aber auch nicht tragbar wegen der Geschwindigkeit.

D.h. ich müsste eine Möglichkeit schaffen, dass CRXI direkt seine SQL Statements an die Applikation senden kann, diese an die Datenbank schickt und das Resultset wieder an Crystal gibt.

Daher wäre meine Idee:

Die Applikation bekommt eine Netzwerkschnittstelle verpasst, so dass ein zusätzlicher Thread auf Port 5678 hört.
Dann schreibe ich einen ODBC-Treiber, der sich auf diesen Port verbinden kann und entsprechende Statements an die Applikation weitergeben kann.

So kann ich in Crystal diesen ODBC Treiber einbinden und damit arbeiten, SQL Statements die CRXI an den ODBC Treiber sendet, landen über die TCP Verbindung in dem Thread der Applikation, hier wird das Statement an die Zeos Library weitergegeben und das Resultset über TCP an den ODBC Treiber zurückgeben.


Damit hätte ich alle Voraussetzungen:
+ Crystal hat eine (vorgetäuschte) SQL Datenbank
+ Statt 10 Statements bei 10 Tabellen die verknüpft werden müssen, wird nur noch ein SQL Statement erzeugt
+ die Datenbank übernimmt dei Datenverknüfung und CRXI muss das nicht mehr selbst machen.


So, zu dieser Vorgehensweise hätte ich ein paar Fragen:

1. Was halten die eingefleischten Datenbanktechniker hier von dieser Idee?
2. Hat jemand einen besseren Vorschlag?
3. Hat jemand mal einen ODBC Treiber entwickelt? ich hab mich damit mal etwas beschäftigt, sieht recht heftig aus, vor allem weil ich ja noch ein eigenes Protokoll entwickeln muss, das die Kommunikation zwischen ODBC Treiber und Applikation herstellt.
4. Sind ODBC Treiber überhaupt zu empfehlen? Irgendwo hab ich gelesen die sind veraltet - aber einen Ersatz hab ich noch nicht gefunden.
5. Angenommen ich habe eine embedded Firebird Datenbank, kann ich maximal eine ZConnection erstellen. ich hab aber die Applikation und meinen zusätlichen Thread für die TCP Verbindungen der die SQL Statements an die Datenbank schicken muss - geht das überhaupt? Ich müsste dann eine ZConnection über zwei Threads benutzen, soweit ich weiß sind die Dinger nicht threadsave - muss ich mir hier meine eigenen Locks einbauen?
6. Lässt sich per ODBC irgendwie die Syntax der generierten SQL Statements festlegen? Zum Beispiel versteht eine Oracle Datenbank nicht alles was Firebird versteht - und umgekehrt. Wie kann ich Crystal sagen wie das SQL Statement aufgebaut sein muss? Oder benötige ich da einen Wrapper im der Applikation die mir den SQL String analysiert und auf die gerade aktive Datenbank umschreibt? -> Gibt es dafür schon Komponenten? die Zeos haben so etwas soweit ich weiß nicht.
  Mit Zitat antworten Zitat