Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Daten aus Datenbank in Speicher halten?! (https://www.delphipraxis.net/165497-daten-aus-datenbank-speicher-halten.html)

hans ditter 2. Jan 2012 23:40

Datenbank: SQLite • Version: 3 • Zugriff über: Delphikomponenten

Daten aus Datenbank in Speicher halten?!
 
Hallo an alle!

Hoffentlich seid ihr gut durch die Feiertage gekommen! ;)

Ich habe mich in den Ferien mit Datenbanken beschäftigt und vor allem damit, wie ich die in eine Delphi-Anwendung einbinde.
Nun hab ich ein Projekt erstellt, dass meine DVDs verwaltet. Hierzu habe ich unter anderem die Tabelle (Tbl) 'Movies' erstellt, die die Informationen zu Titel, Regisseur, Schauspieler, Genre etc. aufnimmt.

Nun hab ich in der Anwendung eine Eingabemaske entworfen, die aus Edits und Memos besteht, die also jeweils nur einen Datensatz anzeigt oder einen neuen aufnehmen kann.

Nun hab ich mich gefragt, wie ich die Daten nun am Besten verarbeite, z.B. beim Navigieren. Im Moment ist es so, dass ich für einen Datensatz zurück die komplette Tabelle ('SELECT * FROM movies;') aus der DB hole und den n-ten Datensatz heraushole (n hab ich mir in einer Variable gemerkt). Danach wird die Tabelle wieder geschlossen.

Diese Art halte ich aus 2 Gründen für ungünstig: 1. es ist extrem umständlich und 2. (wichtiger) wird die Datenbank laufende Meter wieder neu geöffnet, eine neue Abfrage Tabelle erzeugt und dann wieder geschlossen.

Also dachte ich mir, kannste ja auch die ganze Tabelle in ein Programminternes Array speichern und somit immer zur Verfügung haben. Doch da hab ich mir gedacht, dass das ja enorm viel an Ressourcen verbraucht, vor allem wenn es an die tausende Datensätze geht, und es bei Multi-User-Zugriffen auch ein Problem der Aktualität geben könnte.

Nicht alle Dinge (z.B. Multi-User) treffen auf mein Projekt zu, sind ja aber wann anders vielleicht interessant. Also meine allgemeine Frage: Wie holt man sich Daten aus einer Datenbank um sie anzuzeigen, in ihnen zu navigieren und sie zu verändern, ohne z.B. ZEOS zu verwenden.

Die Frage ist halt nich auf mein Projekt speziell bezogen, sondern mehr generell, denn vlt kommt in Zukunft ja mal ein Projekt mit Multi-User und tausenden Datensätzen... ;) man kann ja nie wissen!

LG; hans ditter

RWarnecke 3. Jan 2012 05:38

AW: Daten aus Datenbank in Speicher halten?!
 
Hallo,

Ich schreibe mir dazu Klassen und eine TObjectList. Beim ersten Mal aufrufen, werden alle Datensätze in die TObjectList geladen. Nachher im Programm, navigiere ich nur durch die Objektlist und reagiere auf Veränderungen. Wird eine Veränderung vom Anwender durchgeführt, lade ich nochmal alle Datensätze neu in die ObjectList.

Bummi 3. Jan 2012 06:37

AW: Daten aus Datenbank in Speicher halten?!
 
Das ist doch genau das was Datasets (zumindest Clientseitige) ohnehin tun ...:gruebel:

Furtbichler 3. Jan 2012 07:27

AW: Daten aus Datenbank in Speicher halten?!
 
Für eine Tabelle sollten datensensitive Steuerelemente genau das Richtige sein.

1. Tabellenkomponente auf die Form schmeissen.
2. Mit einer TDatasource-Komponente verknüpfen.
3. TDBGrid auf die Form und mit der TDatasource verknüpfen.
4. Dann noch ein paar TDBEdits und TDBMemos und mit TDatasource verknüpfen.

Starten und staunen, das man so ein Projekt ganz ohne Code hinbekommt.

hans ditter 4. Jan 2012 11:11

AW: Daten aus Datenbank in Speicher halten?!
 
Naja, dass es mit datensensitiven Komponenten geht war mir klar. Es ging mir vor allem um die generelle Umsetzung, wenn man eben keine entsprechenden Komponenten nutzen will.

LG; hans ditter

stahli 4. Jan 2012 11:43

AW: Daten aus Datenbank in Speicher halten?!
 
Hier hatte ich ähnliche Fragen angesprochen: http://www.delphipraxis.net/165090-g...nkprojekt.html
Es ging dann recht munter durcheinander. Es gibt eben unterschiedliche Ansätze, die unterschiedliche Vor- und Nachteile haben und nicht für jedes Projekt gleich bewertet werden können.

Sharky 4. Jan 2012 11:49

AW: Daten aus Datenbank in Speicher halten?!
 
Zitat:

Zitat von hans ditter (Beitrag 1144090)
... Im Moment ist es so, dass ich für einen Datensatz zurück die komplette Tabelle ('SELECT * FROM movies;') aus der DB hole und den n-ten Datensatz heraushole (n hab ich mir in einer Variable gemerkt). Danach wird die Tabelle wieder geschlossen...

Warum holst Du denn die komplette Tabelle wenn Du nur einen bestimmten Datensatz haben möchtest?
Das macht das doch unglaublich langsam. Schliessen musst Du die Verbindung zur Datenbank ja auch nicht.
Beim Programmstart mit der DB verbinden und beim beenden schliessen.
Dazichen immer nur ein SELECT ... das mit Parametern aufgerufen wird.

hans ditter 4. Jan 2012 14:47

AW: Daten aus Datenbank in Speicher halten?!
 
@Sharky: Das war letztlich auch das, was ich problematisch gesehen hab. Die beste Lösung sieht für mich im Moment wie die Antwort von RWarnecke mit Klassen und ObjectList, obwohl mir die Umsetzung noch nicht ganz klar ist...

Was hat die Klasse zu tun? Holt die die Daten aus der DB oder nimmt sie die Daten eines Datensatzes auf oder wie? Und was speicher ich in der ObjectList? Pointer auf die Klasse? Oder irgendwas anderes?

LG; hans ditter

webcss 4. Jan 2012 14:58

AW: Daten aus Datenbank in Speicher halten?!
 
Schau Dir mal z.B. dORM an, dann musst Du das Rad nicht unbedingt neu erfinden.

p80286 4. Jan 2012 17:00

AW: Daten aus Datenbank in Speicher halten?!
 
Lehn Dich doch mal zurück und frag Dich was Du willst.
Wenn Du z.B einen Film suchst, dann fragst Du nach "Doktor Schiwago". Dann interessiert Dich "stirb langsam III" nicht. Es sei denn Du möchtest eine Liste aller Filme (mit Bruce Willis) haben.
Wenn Du diese Anforderungen kennst, - und erst dann!!- solltest Du daran gehen die notwendige Oberfläche zu schreiben.

Gruß
K-H

Mavarik 7. Jan 2012 03:33

AW: Daten aus Datenbank in Speicher halten?!
 
Wie wäre es mit:

Delphi-Quellcode:
'Select * from [$TABLENAME] where FILMNAME LIKE '''+Sucher.Text+'%'' OR SCHAUSPIELER LIKE '''+Sucher.Text+'%'' OR WAHTEVER LIKE '''+Sucher.Text+'%''');


Mavarik

Furtbichler 7. Jan 2012 08:38

AW: Daten aus Datenbank in Speicher halten?!
 
Das beantwortet die Frage nicht.

RWarnecke 7. Jan 2012 09:14

AW: Daten aus Datenbank in Speicher halten?!
 
Zitat:

Zitat von hans ditter (Beitrag 1144321)
@Sharky: Das war letztlich auch das, was ich problematisch gesehen hab. Die beste Lösung sieht für mich im Moment wie die Antwort von RWarnecke mit Klassen und ObjectList, obwohl mir die Umsetzung noch nicht ganz klar ist...

Was hat die Klasse zu tun? Holt die die Daten aus der DB oder nimmt sie die Daten eines Datensatzes auf oder wie? Und was speicher ich in der ObjectList? Pointer auf die Klasse? Oder irgendwas anderes?

LG; hans ditter

Unter diesem Link habe ich mal ein Beispiel gepostet. Die Klasse enthält die Spalten der Tabelle aus der Datenbank. Die Klasse wird dann in der TObjectList gespeichert. Somit enthält die TObjectList alle Datensätze der Tabelle.

ConnorMcLeod 7. Jan 2012 09:19

AW: Daten aus Datenbank in Speicher halten?!
 
Wenn alles in den Speicher passt, dann könnten MemTables z.B. von JEDI helfen.

hans ditter 7. Jan 2012 17:24

AW: Daten aus Datenbank in Speicher halten?!
 
@Connor: Bei meinem Projekt dürfte das wohl noch passen, aber wenn es irgendwann mal größer werden sollte? Ganz allgemein: Wie wird denn das z.B. auch bei den datensensitiven Komponenten gemacht? Halten die die Daten auch die ganze Zeit im Speicher oder sozusagen "just-in-time"?

@RWarnecke: Du sagtest es ja schon, aber nur um sicherzugehen... ;) Die Klassen enthält alle Felder eines Datensatzes aus der Tabelle. Die ObjectList hingegen enthält alle instanziierten Klassen, somit also alle Datensätze der Tabelle?!

- Wird das nich bei größeren Projekten extrem Speicherfressend? Oder wird da immer nur ein Teil der Daten geladen, sozusagen +- 10 Datensätze um den angefragten herum?

- Wenn man die Klasse instanziiert, dann muss sie ja einer Variable zugeordnet werden, ist da dann der Ausdruck
Delphi-Quellcode:
var obj: TKlasse;
begin
  New(obj);
  ...
end;
der richtige Ansatzpunkt?

- Kann man bei Erzeugung einer neuen Klasse selbige auch automatisch an die ObjectList anhängen? Passiert dies bei deinem Bsp. (dein Link) über das NotifyEvent?

LG und vielen Dank schonmal für die Antworten! :)

hans ditter

EDIT:

Mir ist eben noch ein Gedanke gekommen. Jetzt hab ich zwar schön die Grundlage geschaffen, die Daten im Speicher bereit zu halten. Aber wie bekomme ich die überhaupt aus der Datenbank raus? Schreibt man dazu einen alleinstehenden Extracode?
Meine Idee war, eine dritte Klasse 'Database' (o.ä.) zu entwerfen, die die ObjectList enthält und außerdem Methoden bereitstellt, Datensätze zu ändern, zu löschen oder hinzuzufügen. Meiner Meinung nach würde das die Möglichkeit geben, relativ leicht später Datensätze zu bearbeiten. Z.B. müsste man dann im Hauptprogrammcode nur noch ein TMovie-Objekt erzeugen, welches, durch TDatabase, automatisch der Datenbank hinzugefügt wird.

Was haltet ihr von der Idee?

RWarnecke 7. Jan 2012 21:41

AW: Daten aus Datenbank in Speicher halten?!
 
Zitat:

Zitat von hans ditter (Beitrag 1144819)
Die ObjectList hingegen enthält alle instanziierten Klassen, somit also alle Datensätze der Tabelle?!

Jaein, es kommt drauf an, wie Du Sie füllst.

Zitat:

Zitat von hans ditter (Beitrag 1144819)
- Wird das nich bei größeren Projekten extrem Speicherfressend? Oder wird da immer nur ein Teil der Daten geladen, sozusagen +- 10 Datensätze um den angefragten herum?

Der Speicherverbauch ist bis jetzt immer im Rahmen geblieben, egal wieviele Datensätze ich geladen hatte in der TObjectList.

Zitat:

Zitat von hans ditter (Beitrag 1144819)
- Wenn man die Klasse instanziiert, dann muss sie ja einer Variable zugeordnet werden, ist da dann der Ausdruck
Delphi-Quellcode:
var obj: TKlasse;
begin
  New(obj);
  ...
end;
der richtige Ansatzpunkt?

Du nimmst den Quelltext aus meinen obenstehenden Link. Und so fülle ich die TObjectList :
Delphi-Quellcode:
procedure TDM_Main.SetAnsprechpartnerListe(Kundennr : string);
begin
  if AnsprechpartnerListe.Count > 0 then
    AnsprechpartnerListe.Clear;
  with UniQuery_Ansprechpartner do
  begin
    SQL.Text := 'SELECT * FROM Ansprechpartner WHERE Kundennr = :KundenID;';
    ParamByName('KundenID').AsString := Kundennr;
    Open;
    while not Eof do
    begin
      AnsprechpartnerListe.Add(TAnsprechpartner.Create);
      with TAnsprechpartner(AnsprechpartnerListe.Last) do
      begin
        KundenNr := FieldByName('Kundennr').AsString;
        Vorname := FieldByName('Vorname').AsString;
        Nachname := FieldByName('Nachname').AsString;
        Telefon1 := FieldByName('Telefon1').AsString;
        Telefon2 := FieldByName('Telefon2').AsString;
        Fax     := FieldByName('Fax').AsString;
        Mobil   := FieldByName('Mobil').AsString;
        EMail   := FieldByName('EMail').AsString;
      end;
      Next;
    end;
    Close;
  end;
end;
Zitat:

Zitat von hans ditter (Beitrag 1144819)
- Kann man bei Erzeugung einer neuen Klasse selbige auch automatisch an die ObjectList anhängen? Passiert dies bei deinem Bsp. (dein Link) über das NotifyEvent?

Das NotifyEvent nutze ich dazu, wenn Änderungen in der TObjectList gemacht wurden diese in die Datenbank zu übertragen.

stahli 7. Jan 2012 22:39

AW: Daten aus Datenbank in Speicher halten?!
 
Wenn alle Daten im Speicher verwaltet werden können und keine Multiuser-Zugriffe und Transaktionen nötig sind, dann ist es am einfachsten, die Daten in Objekten zu verwalten.
So lässt sich die Geschäftslogik am einfachsten umsetzen. In meinem Framework habe ich einen Klassengenerator eingesetzt, der mir die Klassen anhand einer vorgegebenen Struktur erzeugt.
Damit kann ich sehr flexibel und komfortabel arbeiten.

Die Daten werden in einer Textdatei serialisiert abgelegt und die Daten-Objekte werden beim Einlesen einer Datei neu erzeugt und gefüllt. Es sind damit natürlich keine Mehrfachzugriffe und Transaktionen möglich.

Auf keinen Fall will ich mehr auf eine Datenbindung verzichten. Egal,ob es nun im Detail mit LiveBinding, DSharp, DBControls oder mit meinen odControls erfolgt.
Jedenfalls will ich im Projekt nicht Edit.Text := Person.FirstName und Person.FirstName := Edit.Text schreiben müssen. Der Datentransport zwischen GUI und Datenschicht soll möglichst automatisiert erfolgen.
Daraus kann man auch erkennen, dass ich GUI und Daten künftig immer trennen will.

Passen die Daten nicht (auf jeden Fall) in den Speicher oder sind mehrfache Zugriffe oder Transaktionen erforderlich, sollte man eine Datenbank verwenden (dafür sind sie ja da).
Über einen SQL-DB-Server kann man Joins über mehrere Tabellen abrufen und die Daten filtern oder Mengen bearbeiten.

Der einfache Weg ist dann, DBControls zu verwenden. Man kann halt recht wenig zaubern und hat i.d.R. immer den Fokus auf einem Datensatz.
Die Geschäftslogik realisiert man über SQL-Statements, was - ja na - auf jeden Fall umständlich ist.

Deshalb gibt es ORM-Lösungen (bekannte Beispiele sind wohl mORMot und DORM), die den Programmierer mit Objekten arbeiten lassen, die Daten aber in einer Datenbank gespeichert werden. Dann ist die Frage, wann die Daten-Objekte erzeugt werden und wie lange sie am Leben bleiben. Auf jeden Fall macht es natürlich Aufwand, die Objekte zu erzeugen und die Daten hin und her zu schaufeln. Die Frage ist auch (für mich), wie mit Versionsänderungen umgegangen wird. Was ist, wenn ich ältere Daten in meinem aktuellen Projekt öffnen will? Außerdem hat das Konzept seine Grenzen wohl bei sehr großen Datenbanken.

Wenn die Geschäftslogik sehr komplex ist und die Daten nicht übermäßig umfangreich sind, ist eine ORM-Lösung sicher sinnvoll.
Ein Databinding sollte dann auch wieder geregelt werden.

Steht die Datenbank im Vordergrund, ist ein ORM-Einsatz sicher nicht sinnvoll. Eine Bank wird ihre Konten wohl mit einer klassischen DB-Anwendung verwenden.

Wenn schon "normale DB-Anwendung", dann kann man überlegen, ob man einfach per Clients auf die DB zugreift oder eine mittlere Schicht bereitstellt, die die Geschäftslogik enthält und ihrerseits auf die DB zugreift (Multi-Tier-Anwendung). Die Clients sind dann quasi nur noch zum Anzeigen und Bearbeiten der Daten da.

Alles hat seine Vor- und Nachteile und ist mit unterschiedlichen Aufwänden verbunden.

Deshalb kann man wohl nie so einfach sagen, was man "ab besten" einsetzen soll...

Soweit mal meine Einschätzung der Sachlage. ;-)

Chemiker 8. Jan 2012 00:24

AW: Daten aus Datenbank in Speicher halten?!
 
Hallo hans ditter,

ich kenne jetzt nicht die Datenbank SQLite. Aber ich vermute, dass damit ganz normale Abfragen über SQL möglich sind.

Eine andere Möglichkeit um alle Daten im Speicher zu halten ist mit TClientDataSet . Damit kann man einen gesamten Datenbestand aus der DB in den Speicher lesen und wenn man will auf die lokale Festplatte speichern.

Bis bald Chemiker

BUG 8. Jan 2012 16:38

AW: Daten aus Datenbank in Speicher halten?!
 
Das Vorgehen: alle Daten holen, in Speicher bearbeiten / Anfragen machen und wieder zurückschreiben macht die Nutzung einer Datenbank absurd. Damit eleminierst nahezu alle Vorteile, die dir eine Datenbank bietet.

Und Caching sollte bei einer lokalen Datenbank wie sqlite nur in Ausnahmefällen etwas bringen.

Furtbichler 8. Jan 2012 19:19

AW: Daten aus Datenbank in Speicher halten?!
 
Na ja, wenn man sich merkt, welche Daten verändert wurden, ist das Zurückschreiben doch kein Problem.
Und "Alles im Speicher halten" ist -je nach Anwendung und Definition von "Alles"- manchmal auch sinnvoll.

Wir müssen (bzw. wollen) bis zu 5000 Aufträge im Speicher halten, weil die Disponenten beim Anruf eines Kunden schnell die richtigen Aufträge finden müssen. Eine Query dauert dann leider doch etwas, weil auch Großkunden mit mehreren Hundert Aufträgen dabei sind. Und pro Auftrag sind es 300-400 Details, die mit geladen werden, also schon einiges an Daten.

Hier definieren wir "Alles" mit "alle noch nicht fakturierten Aufträge" und schon ergibt das Konzept Sinn.

BUG 8. Jan 2012 23:21

AW: Daten aus Datenbank in Speicher halten?!
 
Zitat:

Zitat von Furtbichler (Beitrag 1144939)
Wir müssen (bzw. wollen) bis zu 5000 Aufträge im Speicher halten, weil die Disponenten beim Anruf eines Kunden schnell die richtigen Aufträge finden müssen. Eine Query dauert dann leider doch etwas, weil auch Großkunden mit mehreren Hundert Aufträgen dabei sind. Und pro Auftrag sind es 300-400 Details, die mit geladen werden, also schon einiges an Daten.

Das Finden und Filtern der Aufträge sowie das Einpflegen der Änderungen sollte ja möglichst bereits in der Datenbank geschehen. Durch das Bearbeiten im Client gibt es ja einige Probleme:
  • Zumindest die Übertragung großer Datenmengen.
  • Redundanz (Clientdaten <-> Serverdaten), dadurch vielleicht unterschiedliche Version bei verschiedenen Nutzern.
  • Keine Transaktionen.
  • Geänderte Daten sind nicht crashsave in der Datenbank, sondern liegen beim Client im Speicher.

Andererseits könnte man das Ganze als Caching* bezeichnen, was ja nötig sein kann, wenn der Rechner schlecht an das Datenbanksystem angebunden ist.
Aber bei einer lokalen Datenbank sollte es in den meisten Fällen Schwachsinn sein.

* Obwohl ich 5000+ Datensatze irgendwie schon ziemlich extrem finde.


Achtung:
Das ist die Sicht, die ich aktuell nach dem Genuss einer (einzigen) Datenbankvorlesung habe.
Ich will nicht behaupten, dass du bei deinem konkreten Anwendungsfall etwas falsch machst.

Furtbichler 9. Jan 2012 07:27

AW: Daten aus Datenbank in Speicher halten?!
 
Alle diese Probleme sind gelöst, durch Recordlocking, transaktionssicheres Ändern etc.

Die 5000 Datensätze quasi live zu zeigen waren auch wirklich ein ganz schönes Problem, vor allen Dingen das clientseitige Sperren in der GUI.

In einer lokalen DB kann es auch nötig sein, eine in-Memory Kopie der Daten zu haben. So eine lokale DB benötigt ja auch einiges an Zeit, leider.

hans ditter 9. Jan 2012 16:43

AW: Daten aus Datenbank in Speicher halten?!
 
Ich hab grad so in den letzten Beiträgen rausgehört, dass mein Vorhaben Irsinn ist. Aber dann würde ich euch gerne mal fragen, wie man das dann am Besten löst. Es ging mir vor allem darum, dass man durch die Datensätze navigieren kann.
Mein erster Ansatz war dann ja, dass ich einfach für den nächsten bzw. vorigen Datensatz eine neue Abfrage starte.
Der zweite Ansatz war dann jetzt, die Daten aus der DB in den Speicher zu ziehen (z.B. mit Klasse und ObjectList) um einfach navigieren zu können, ohne die DB bei jedem Vor/Zurück anzusprechen.

Ist das nicht der richtige Ansatz? Denn letztlich muss doch ein StringGrid o.ä. die angezeigten Daten auch im Speicher halten...

nachti1505 12. Jan 2012 11:43

AW: Daten aus Datenbank in Speicher halten?!
 
Ich unterstelle jetzt einfach mal keine jahrelang CodingXperience. In diesem Fall würde ich dringend auf die datensensitiven Controls von Delphi verweisen. Einfacher kann man eine derartige Applikation nicht entwerfen.

Auch hier werden je nach Implementation die Daten im Speicher gehalten (TDataset-Nachfahre), allerdings sind das erprobte Komponenten. Die TObjectList-Lösung ist imho schon um einiges aufwendiger zu programmieren.

hans ditter 12. Jan 2012 14:50

AW: Daten aus Datenbank in Speicher halten?!
 
@Nachti: Einfacher ist es in jedem Fall... aber darum geht es ja gerade: ich will lernen, also nehm ich nicht immer den einfachsten Weg.
Ich hab diesen Thread nicht aufgemacht um möglichst schnell mein Programm fertig zu bekommen, sondern um bessere Alternativen kennenzulernen und sie umzusetzten.

Zu dem zweiten Teil deines Posts: werden die Daten nur bei bestimmten Datensensitiven Komponenten im Speicher gehalten? Ich frage, weil du schriebst "TDataset-Nachfahren" und "je nach Implementation".

LG; hans ditter


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:09 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz