Autor Beitrag
trm
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 491
Erhaltene Danke: 19

Windows 7x64
Delphi 7
BeitragVerfasst: Mi 27.01.10 16:55 
Hallo,

kann mir bitte jemand kurz erläutern, wie eine Datenbankspeicherung funktioniert, wenn keine Datenbankobjekte als Eingabe benutzt wird?

Bei meinem Fall iseht es so aus, dass ein Anwender sich Daten für einen bestimmten Tag in einem TStringGrid anzeigen lässt. Diese Daten können geändert werden. bei einer Speicherung der Daten wird das aktuell ausgewählte Datum, der Name des TStringGrids sowie die aktuell zu verarbeitende StringGrid-Reihe als Index herangezogen.

Dies funktioniert einwandfrei, es kann mit diesem Verfahren keinerlei inkonsistenz in der Tabelle geben.

Nun versuche ich aber die ganze Sache über ein Netzwerk laufen zu lassen, die Datenbank kann also von 2 Benutzern geöffnet werden. Sollten durch Zufall beide Nutzer zur gleichen Zeit den gleichen Tag zur Ansicht haben, dann kann folgendes passieren:
Nutzer1 ändert Daten. Nutzer 1 speichert die Daten.
Nutzer 2 hat die alten Daten immer noch offen. Nutzer 2 ändert ebenfalls Daten. Nun speichert Nutzer2 die Daten.
Somit ergibt sich eine Situation, welche aufzeigt, dass hier eine Prüfung rein muss.

Wie gestaltet man dies?

Meine eigene Idee wäre, dass ich einen Zeitstempel in der Datenbank für den jeweils angezeigten Tag hinterlege. Dies setzt jedoch vorraus, dass beide PC die gleiche Uhrzeit haben. Oder aber, ich speichere den alten Zeitstempel in einer Variablen, gleiche die Variable VOR dem nächsten speichern mit der aktuellen in der Datenbank ab und kann nun weiter entscheiden. Aber wie entscheidet man sich dann :( ?

Ich hoffe, ich konnte mein Dilemma ein wenig deutlich machen. Für Hinweise bin ich sehr dankbar :)

Liebe Grüße
~Mathias
JDF
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 29

WinNT, Win2k, WinXP, Win2003
d6ent, d7pro, bds2006ent, vs2003
BeitragVerfasst: Mi 27.01.10 18:47 
Hallo!

die Lösung mit dem Zeitstempel funktioniert, wenn Du den Zeitstempel von der Datenbank verwalten lässt.

Aber eine praktikable Lösung ist auch die Verwendung eines Versionszählers vom
Typ Integer oder SmallInt, der auch weniger Platz in deiner Datenbank beansprucht.
Die Prüfung des Versionszählers kannst Du in einen Before-Update-Trigger packen,
der bei OLD.Version <> NEW.Version eine Datenbank-Exception auslöst und bei
Gleichheit deinen Versionszähler um 1 erhöht.

Der Zeitstempel oder der Versionszähler müssen als extra Feld deiner Tabelle hinzugefügt werden.

Gruß
Jürgen
trm Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 491
Erhaltene Danke: 19

Windows 7x64
Delphi 7
BeitragVerfasst: Mi 27.01.10 19:51 
Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Hallo Jürgen,

Danke für Deine Antwort :)

Die Datenbank verwaltet den Zeitstempel doch nur selbst, wenn sie eine externe ist, z.B. auf SQL aufbaut, oder?
Somit kann ich dies nicht nutzen, weil TDbf (sourcheforge) eine in die binray einkompilierte Datenbank ist, welche ohne Treiber und externe Quellen auskommt.

Die Sache mit dem integer verstehe ich nicht ganz. Eine Prüfung mit einer erhöhung um 1 führt doch (technisch gesehen) irgendwann zu einem Überlauf, oder?
Auch das Prinzip an sich ist mir unklar. kannst Du mir hierzu eine Lektüre (im Internet) empfehlen, welche nicht in einem Buch endet?

Danke, viele Grüße
~Mathias
JDF
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 29

WinNT, Win2k, WinXP, Win2003
d6ent, d7pro, bds2006ent, vs2003
BeitragVerfasst: Do 28.01.10 11:34 
Hallo Mathias,

sorry, ich hatte die Verwendung der TDbf-Komponenten auf Basis von dBase-Dateien übersehen.

Meine Ausführungen passen auf eine SQL-Datenbank, die Trigger unterstützt.
Ich kann von Dir keinen Datenbankwechsel verlangen.

Eine Lektüre kann ich Dir nicht empfehlen, da die Lösung
mit dem Versionszähler im praktischen Einsatz entstand.
Noch ein paar Worte zum Verständnis:

- Die Erhöhung um 1 kann zu einem Überlauf führen. Aber
wie oft wird ein Datensatz in der Datenbank geändert?
z.B. wenn ein Auftrag abgerechnet ist, dann sind
Veränderungen an dem Auftrag sehr unwahrscheinlich
und der Überlauf wird nie vorkommen
Also: Änderungsbedarf pro Datensatz abschätzen
(SmallInt: ~32000 Änderungen pro Satz)

- Wenn Du keinen Trigger einsetzen kannst, dann könnte
mit dem BeforePost-Ereignis des TDataSet die Versionsprüfung
ausgeführt werden

- Wenn n User einen Datensatz mit der Versions X zum Bearbeiten
gelesen haben, verändert jeder User die Daten auf der Basis der
Version X und versucht dann mit der Version X zu speichern.
Der erste User, der speichert, erzwingt das Erhöhen der Version
auf den Wert X+1. Jeder weitere User, der mit der Version X das
Speichern versucht, wird wegen Ungleichheit der Versionsnummer
von der Datenbank (z.B. SQL-Trigger) abgewiesen.

Du kannst versuchen ob die Überprüfung im BeforePost und die
Erhöhung um 1 im AfterPost funktioniert.
(keine Garantie, da ich die TDbf-Komponenten nicht kenne)

Ich hoffe, das hilft Dir weiter.

Gruß
Jürgen
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Do 28.01.10 13:29 
user profile iconJDF hat folgendes geschrieben Zum zitierten Posting springen:

Du kannst versuchen ob die Überprüfung im BeforePost und die
Erhöhung um 1 im AfterPost funktioniert.

Das müsste eigentlich funktionieren. Ich hatte mal vor Ewigkeiten eine kleine Paradox-Datenbank im Einsatz und für eine Anwendung im BeforePost eine Prüfroutine eingebaut. Im Fehlerfall habe ich mit raise eine Exception ausgelöst, wodurch das Post nicht ausgeführt wurde.
trm Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 491
Erhaltene Danke: 19

Windows 7x64
Delphi 7
BeitragVerfasst: Do 28.01.10 13:30 
Hallo Jürgen,

diese Erklärung habe ich verstanden, vielen Dank. Auf dieser Basis, vor allem, da die Datenbank eher relativ klein bleiben wird (auch über viele Jahre hinweg), habe ich mir einen anderen Weg versucht zu erarbeiten.

Ich generiere einen Zufallsstring (Länge 10-20 zeichen) und speichere diesen pro Datenbankzeile (StringGrid-Zeile). Dadurch kann ich, denke ich davon ausgehen, dass ähnlich Deinem Vorschlag immer ein Status ermittelt werden kann und keine Fehler auftreten.

Ich muss mir nun nur noch eine Möglichkeit überlegen, wie ich die Intigrität der Daten bei einer Speicherung beibehalte, ohne Datenverlust zu verursachen. Dies könnte ich mit einer Benutzerrückfrage erreichen, bei der nachgefragt wird, ob die alte (neuere) Version beibehalten wird, bzw., ob die eigene Änderung Vorrang hat.

Gruß
Mathias :)