ADOConnection: Dynamischer Connectionstring

    ADOConnection: Dynamischer Connectionstring

    Guten Tag,
    ich würde gerne den Connectionstring und damit den Ort der Datenbank dynamisch halten.
    Ich habe eine Form in der ich die INI-Datei auslese und den darin befindenden Pfad, der zur Datenbank führt in ein Edit Feld schreibt.
    Des Weiteren kann ich über ein Opendialog einen neuen Dateienpfad zu der Datenbank in die INI-Datei schreiben.
    Nun würde ich gerne, dass ich mit dieser Option nun den Connection String erstelle, damit dann in Run Time ich den Ort ändern kann und dennoch die ADO Connection Komponente auf jeder Form auf die Datenbank zugreifen kann.

    Der ConnectionString hat den Aufbau:

    Quellcode

    1. DBQ=Dateienpfad zur Datenbank\Datenbankname.mdb
    2. ;DefaultDir=Dateienpfad zum Ordner der Datenbank;
    3. Driver={Driver do Microsoft Access (*.mdb)};
    4. DriverId=25;
    5. FIL=MS Access;
    6. FILEDSN=Dateienpfad zur DSN Datei\Datenbankname.mdb.dsn;
    7. MaxBufferSize=2048;MaxScanRows=8;PageTimeout=5;SafeTransactions=0;Threads=3;UID=admin;UserCommitSync=Yes;


    Nun meine Frage: Also wie ich den Pfad dynamisch mache ist mir wohl klar, ich würde für die Pfade einfach Variablen setzen und diese damit füllen.
    Doch mir ist unklar, wie ich die dsn Datei erstelle bzw. diese muss ich ja auch irgendwie dynamisch machen.
    Des Weiteren frage ich mich, wie ich im Entwicklungsmodus im Objektinspektor den Connectionstring so einstelle, dass er dynamisch wird. Soll ich dann einfach irgendeinen Connectionstring dort rein schreiben und den über den Programmcode im Start des Programmes und damit im Laden der Ini-Datei den neuen Connectionstring setzen?

    Ich hoffe Ihr könnt mir da weiterhelfen! Eventuell hat hier jemand schon mal das gleiche bereits vorgehabt und umgesetzt und kann mir da aushelfen!
    Moin... 8o

    Das mit dem DSN höre ich heute zum ersten Mal. Ich denke, daß in der DSN auch nur der Connection String steht... oder? ?( Normalerweise muß du nur den Pfad austauschen. Disconnect, Wechseln, Connect...
    Für den Pfad bietet sich FORMAT('..., %s,...', [Pfad]) an.

    Ansonsten hätten wir noch etwas aus der Konserve... delphi-treff.de/tutorials/date…g-einer-access-datenbank/

    Hänge mal die DSN als Beispiel an. Danke...

    8)

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „haentschman“ ()

    Erstmal dankeschön!

    Aber du hast recht in dieser Datei steht nur das was im String steht noch mal im Aufbau eines Wertepaares mit Schlüssel und Wert und einer Sektion:

    Delphi-Code

    1. [ODBC]
    2. DRIVER=Driver do Microsoft Access (*.mdb)
    3. UID=admin
    4. UserCommitSync=Yes
    5. Threads=3
    6. SafeTransactions=0
    7. PageTimeout=5
    8. MaxScanRows=8
    9. MaxBufferSize=2048
    10. FIL=MS Access
    11. DriverId=25
    12. DefaultDir=...
    13. DBQ=Pfad\Name.mdb


    Wenn man das manuell macht und eine neue Datenbank benutzt verändert sich da nicht auch die Werte wie: DriverID, MaxBufferSize, Theards usw.?
    Also würde man schlichtweg einfach eine Datei erstellen mit den Schlüssel und Werten und dann als *.mdb.dsn abspeichern? Weil anscheinend muss ja die DSN Datei im gleichen Ordner sich befinden wie die Datenbank.
    Und danach würde man den String erstellen anhand der Schlüssel und Werte aus der DSN Datei?

    Was in diesem Tutorial beschrieben ist verwundert ich mich etwas, weil wenn man die Datenbank auswählt und über Delphi den Connectionstring erstellt, dann bleibt dieser ja eingespeichert und muss nicht neu eingegeben und somit nicht in der Registry hinterlegt werden.
    Meine Absicht ist da ja eine andere nämlich diese, dass ich zur Laufzeit und über ein Opendialog Fenster die neue Datenbank auswählen möchte und das diese dann in der INI-Datei hinterlegt wird! :D
    Hallöle... 8)

    Mach es dir nicht so schwer. Du denkst zu kompliziert. :P

    Du hast mehrere Varianten zur Auswahl:

    1: Verabschiede dich dem DSN File. Der Connection String hat alle Informationen für den Treiber und das Datenbankfile. Die anderen Werte (MaxBufferSize etc.) können schon in der Connection mit dem OI festgelegt werden. 8o
    (mein Favorit)
    2: Du macht dir für jede Datenbank ein neues DSN File nach dem OpenFile mit allen Informationen.
    3: Du hast nur ein DSN File. Die Werte für das Datenbankfile werden nach dem OpenFile ausgetauscht.

    Für Variante 1 bietet sich FORMAT('..., %s,...', [Pfad]) an. Beispiele für Connection Strings gibt es haufenweise im Netz.
    Beispiel: 'Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccessFile.mdb';

    Für Variante 2,3 bietet sich eine Stringlist an.

    Hinweis:
    Disconnect, Wechseln, Connect ist immer nötig!

    Frage hinzugefügt

    Erstmal danke Euch beiden!

    cckLoud schrieb:

    Wenn du nicht alle Parameter des Connection-Strings brauchst, sondern zB nur den DB-Pfad anpassen willst , gibts noch einen weiteren (einfacheren) Weg:Erfasse im OI den "richtigen" string und gibt für den Pfad enfach einen Platzhalter ein, also zB"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=***;Persist Security Info=False"Den Platzhalter *** ersetzt du dann vor dem Connect einfach per "Stringreplace" durch den Pfad...cckLoud


    Das klingt sehr einfach und da ich ja nur den Datenbank Ort ändern muss, würde das ausreichen.

    Oder was noch einfacher wäre für mich:

    Delphi-Code

    1. NewConnectionString := ADODB.PromptDataSource(0, Connection.ConnectionString);

    Da ich ja als "Admin" des Programmes von meinem Adminbereich aus den Datenbank Ort ändere, könnte ich ja auch einfach über ein Button das Dialog Fenster zum Aufbau einer Verbindung aufrufen, mir die Datenbank neu raussuchen und dann wird ja nicht nur der Connection-String erstellt, sondern auch die DSN File und ich muss mich darum nicht mehr kümmern.

    Ich glaube ich würde mich für Fall 2 entscheiden.
    Korrigiert mich wenn ich falsch liege:
    1. Dafür müsste ich nur in jede Form im OI das Connection := False stellen,
    2. im OnCreate die INI-File auslesen (Dort speichere ich dann mein aktuellen Connection String),
    3. den Connection String setzen und Connection := True.
    4. Im Admin Bereich dann beim auswählen einer neuen Verbindung Connection := False (Für alle Formen oder nur für die Admin-Form?),
    5. dann Dialogfenster zur Datenbankverknüpfung aufrufen,
    6. String auswählen,
    7. diesen dann in die INI speichern,
    8. Connectionstring setzen und Connection := True.
    Fertig?

    // Edit:
    Aber muss ich überhaupt die Connection beenden, wenn es eine Access Datenbank ist? Ist das die KeepConnection Eigenschaft oder welche?

    Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „Asura“ ()

    Moin... 8o
    Ich komme mit deinen Argumenten nicht mit... ?(
    Was ist einfacher...Ein TOpenDialog mit der Auswahl des Datenbankfiles und der Speicherung in die INI (hast doch schon) oder das Gedöns mit dem DSN File?

    Wenn du nicht alle Parameter des Connection-Strings brauchst, sondern zB nur den DB-Pfad anpassen willst

    ...das ConnectionString Muster kannst du im Datenmodul als Konstante definieren. Eleganter als StringReplace ist, wie ich schon sagte, FORMAT('..., %s,...', [Pfad]) .
    docwiki.embarcadero.com/Librar…de/System.SysUtils.Format

    im OnCreate die INI-File auslesen ...den Connection String setzen und Connection := True

    ... mehr braucht es nicht. 8)

    sondern auch die DSN File und ich muss mich darum nicht mehr kümmern.

    ...wer räumt die DSN wieder weg wenn sie nicht mehr gebraucht werden? Manuell? Nochmal: du brauchst es nicht! :/

    könnte ich ja auch einfach über ein Button das Dialog Fenster zum Aufbau einer Verbindung aufrufen

    ...wieder ein zusätzlicher Dialog der nicht benötigt wird. :/

    Für alle Formen oder nur für die Admin-Form?

    ...siehe Bild. 8)

    Aber muss ich überhaupt die Connection beenden

    Wenn du die Datenbank wechselst, mußt du die Connection neu auf bauen.

    Ist das die KeepConnection Eigenschaft oder welche?

    docwiki.embarcadero.com/Librar…Connection.KeepConnection
    Bilder
    • Diagramm.png

      11,83 kB, 438×681, 16 mal angesehen

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „haentschman“ ()

    Hey! Also wieder einmal ein Dankeschön für die Zeit, die du mir für die Hilfe schenkst !

    Das erste Beispiel würde auf das mit FORMAT gehen!

    Aber da ich eh manuell die Datenbank ändern muss (Selbst das würde sehr sehr selten vorkommen), habe ich die Möglichkeit 2 gefunden. Die öffnet aus der ADODB Unit das Dialog Fenster, welches man normalerweise über den OI öffnet, um einen ConnectionString zu erstellen! Also sehr sehr simpel, da ich das vllt mal einmal im Jahr machen muss, reicht das aus.
    Das ist also nicht die TOpenDialog - Komponente, sondern das Dialog Fenster, welches Delphi nutzt, um ADO Pfade auszuwählen (Also mit Treiberauswahl, Pfad, DSN Erstellung, ConnectionString Erstellung und sogar mit Datenbank-Verbindungs-Test).

    Bis jetzt sieht das auswählen der Datenbank so aus:

    Delphi-Code

    1. procedure TF_Admin1.btn_openClick(Sender: TObject);
    2. begin
    3. ADOConnection.ConnectionString := edt_Database.Text;
    4. ConnectionStr := ADODB.PromptDataSource(0, ADOConnection.ConnectionString);
    5. edt_Database.Text := ConnectionStr;
    6. ini.WriteString('Settings','Database',ConnectionStr);
    7. end;


    edt_Database wird vorher im ONSHOW Event bereits gefüllt durch die INI. Die Zuweisung ist deshalb da, weil ich dann beispielsweise bereits zwei Schritte im Dialogfenster mir erspare, da die Unit ADODB mit dem Dialogfenster

    Delphi-Code

    1. DODB.PromptDataSource(0, ADOConnection.ConnectionString);
    bereits erkennt, dass es sich hierbei um eine Access Datenbank handelt und ich erspare das mir mit dem Treiber bzw. Grundeinstellungen.

    Nun meine Frage zu deiner Grafik:
    Also ich habe anscheinend das etwas falsch gemacht. Ich habe auf jeder Form in der ich auf die Datenbank zugreife eine ADOConnection-, ADOQuery-, Datasource-Komponente.
    Ich interpretiere aus deiner Grafik aber, dass die Formen einfach nur auf die jeweils nur eine Komponente zugreifen?
    Wie entscheide ich nun dann, wo diese eine Komponente dann gesetzt wird? Also eine Form, wo die Datenmodule drauf sind und die anderen Formen haben unter uses dann diese Form "Datenmodule" stehen und nutzen diese?

    Bezüglich dem Reconnect habe ich mir das überlegt, was denkst du dazu?

    Delphi-Code

    1. procedure TF_Admin1.Reconnect(var AdoConn: TAdoConnection; ConnStr: String);
    2. begin
    3. if Assigned(AdoConn) then
    4. begin
    5. FreeAndNil(AdoConn);
    6. AdoConn := TAdoConnection.Create(Self);
    7. AdoConn.ConnectionString := ConnStr;
    8. AdoConn.LoginPrompt := false;
    9. SetConnAdoComponent(Self,AdoConn);
    10. AdoConn.Open;
    11. end;
    12. end;


    Vllt. etwas "radikal" die TADOConnection komplett zu ersetzen?
    In der Delphi-Welt packt man die ganzen nicht-visuellen Komponenten wie z.B. DB-Connections, Queries, etc. auf ein eigenes Datenmodul und bindet dieses dann dort ein, wo man auf die Daten zugreifen möchte. So hat man alles an zentraler Stelle und muss auch nur dort evtl. Änderungen einpflegen.
    10 Minuten Nachdenken ersparen oftmals 10 Stunden Fehlersuche.
    Hallöle... 8o
    Also ich habe anscheinend das etwas falsch gemacht.

    ...das fällt unter learning by doing. 8)

    Ich interpretiere aus deiner Grafik aber, dass die Formen einfach nur auf die jeweils nur eine Komponente zugreifen?

    Korrekt, wenn du die AdoConnection meinst. Mehrere Connection sind wie verschiedene User (berichtigt mich wenn ich falsch liege :whistling: )...und das kann bei Access in die Hose gehen. Mehr als eine Connection ist eher der Ausnahmefall.

    Also eine Form, wo die Datenmodule drauf sind

    Ein Datenmodul ist ein Datenmodul und keine Form. Das Datenmodul dient nur als Container für die Komponenten.
    docwiki.embarcadero.com/Librar…ystem.Classes.TDataModule

    und die anderen Formen haben unter uses dann diese Form "Datenmodule" stehen und nutzen diese?

    Korrekt, wenn du die Connection auf dem Datamodule meinst. Wenn du das Datamodule in den uses deklariert hast, dann kannst du bei der Query auf der Form1 die Connection aus dem Datamodule im OI auswählen.

    Bezüglich dem Reconnect habe ich mir das überlegt, was denkst du dazu?

    Normalerweise sollte ein Connection.Disconnect + Connection.Connect reichen. Ob sich Access da zickig hat, kann ich nicht beurteilen.



    Nachtrag:
    So hat man alles an zentraler Stelle und muss auch nur dort evtl. Änderungen einpflegen.

    So sollte es sein. Die Realität sieht etwas anders aus. :whistling:

    Also kann ich davon ausgehen, dass dann auch die Timer und die Opendialoge beispielsweise dazugehören?

    Danach füge ich einfach nur noch die Unit vom TDataModule in die uses der einzelnen Formulare, wo ich die Datenbankverbindung benötige und rufe die Beispielsweise für dm (Datamodule) so auf: dm.ADOQuery.SQL.Text := [...]
    Also ich sehe schon mal einen Vorteil darin, da ich dann ja alle nicht-visuellen Komponenten an einem Ort habe. Aber die Verarbeitung bzw. das Arbeiten der Komponenten findet dennoch auf den Formen statt, wo ich diese benötige oder werden auch die Funktionen und Prozeduren im Besten Fall so geschrieben, dass man die vom Datenmodul aufruft?
    Also worum nun meine Anfänger Frage gilt: Ab wann unterscheidet man, wo man nun genau mit den Komponenten arbeitet: Über das Datenmodul oder über die eigenen Units der einzelnen Formen?
    Mich verwirrt nämlich das etwas:

    DeddyH schrieb:

    So hat man alles an zentraler Stelle und muss auch nur dort evtl. Änderungen einpflegen.
    Also kann ich davon ausgehen, dass dann auch die Timer und die Opendialoge beispielsweise dazugehören?

    ...ja.

    Danach füge ich einfach nur noch die Unit vom TDataModule in die uses der einzelnen Formulare, wo ich die Datenbankverbindung benötige und rufe die Beispielsweise für dm (Datamodule) so auf: dm.ADOQuery.SQL.Text := [...]

    ...ja.

    Aber die Verarbeitung bzw. das Arbeiten der Komponenten findet dennoch auf den Formen statt, wo ich diese benötige oder

    ...ja.

    werden auch die Funktionen und Prozeduren im Besten Fall so geschrieben, dass man die vom Datenmodul aufruft?

    ...nein. Du benutzt nur ein bestehendes Objekt (z.B. Query ) auf dem Datenmodul. Die Verarbeitung des Abfrageergebnisses findet in der Form (besser in der Logik) statt.

    Ab wann unterscheidet man, wo man nun genau mit den Komponenten arbeitet

    ...kannst du das nochmal erklären wie du das meinst?
    Das hat sich dann damit erledigt!
    Weil ich wollte nur wissen, ob man nun die Verarbeitung der Komponenten auf dem Datenmodul macht oder doch wie ich das jetzt auch habe auf der Form.
    Habe das nun auch alles umgestellt wie hier angeraten und funktioniert auch super. Habe auf jedenfall hier einen großen Mehrwert erlangen dürfen.
    Dafür ein großes Dankeschön!