Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Interbase Generatorwert zurücksetzen? (https://www.delphipraxis.net/39868-interbase-generatorwert-zuruecksetzen.html)

plautzer 8. Feb 2005 15:13

Datenbank: Interbase • Zugriff über: IbStoredProc, IBDataSet

Interbase Generatorwert zurücksetzen?
 
Hi Leutz,

ich habe ein SrtingGrid in dem ich Daten eintragen will.
Falls ich einen neuen Datensatz eintrage, wird die ID automatisch durch den Generator hochgesetzt.

Wenn sich der Benutzer es aber anderes überlegt und gar keinen datensatz anlegen will (also cancel), dann soll die ID wieder zurückgesetzt werden um riesige Lücke zu vermeiden.

Kann man den Generator wert irgentwie von Delphi aus festlegen?

Mir würde jetzt keine eleganten Weg einfallen, wie das lösen könnte, wüsstet ihr einen?

Thx,

Plautzer

[edit=sakura] [Klammern] aus dem Titel entfernt. Mfg, sakura[/edit]

lume96 8. Feb 2005 15:37

Re: [Interbase] Generatorwert zurücksetzen?
 
Moin,

einen Generator-Wert kann man wie folgt setzen :
SQL-Code:
SET GENERATOR abc_GEN TO x;
wobei abc_GEN der Generatorname ist und x der neue Wert

Im Allgemeinen würde ich aber davon abraten, ausser wenn Du Dir absolut sicher bist, dass NIEMAND sonst auf die DB zugreift (z.B. zweite Instanz Deines Programms). Sonst kann es schnell Probleme geben, z.B.:

App 1 nimmt den Wert 5 (nächster Gen-Wert ist jetzt 6)
App 2 nimmt den Wert 6 (nächster Gen-Wert ist jetzt 7)

App 1 will den Generator-Wert zurückseten, aber auf was ???

Musst Du den den Wert so "früh" erfragen. Logischer wäre es, den Wert erst dann zu erfragen, wenn der User den Record schon gepostet hat, Du also sicher bist, dass die Werte in die DB sollen.

Unter Umständen könnte man das sogar über'n Trigger (Before Insert) automatisieren.

Tschüss,
Lutz

Quake 8. Feb 2005 16:03

Re: [Interbase] Generatorwert zurücksetzen?
 
Bei TIBQuery gibt es die Eigenschaft GeneratorField. GeneratorField wiederum besitzt die Eigenschaft ApplyEvent. Setzt du diese auf gamOnPost wird der Wert erst generiert, wenn der Datensatzt auch gespeichert wird.
Oder wenn du den Generatorwert manuell holst dann mache das im onBeforePost Ereignis.

DelphiDeveloper 8. Feb 2005 19:55

Re: [Interbase] Generatorwert zurücksetzen?
 
Wie Lume96 bereits geschrieben hat, kann man aus Delphi heraus auch Generatorenwerte setzen.

Für dein beschriebenes Problem wuerde ich davon auch abraten. Luecken machen ueberhaupt nichts bei einer ID die ja meist ja PK fungiert.
Beabsichtigst du sowas wie eine eindeutige lueckenlose sequenz wie etwa RechNr zu generieren, sind Generatoren dafür nicht geeignet.

mfg
DD

urs.liska 8. Feb 2005 22:02

Re: [Interbase] Generatorwert zurücksetzen?
 
Ich kann mich den Vorrednern nur anschließen:
automatisch hochgezählte Werte sollte man auf keinen Fall von Hand ändern. Das gibt irgendwann eine korrupte Datenbank. Wirklich!

Wenn Du wirklich lückenlose Zahlenfolgen brauchst - wie eben die genannte Rechnungsnummer - dann solltest Du zwei separate Felder benutzen: Eines für den Primärschlüssel (mit Generator) und ein zweites für die lückenlose Folge (die Du auf irgendeine andere Weise programmseitig erzeugen musst).

MfG
Urs

Quake 9. Feb 2005 07:36

Re: [Interbase] Generatorwert zurücksetzen?
 
@urs.liska: Die Frage ist nur wie möchtest du sonst solch eine Zahl erzeugen? Ich denke, wenn man im Netzwerkarbeitet und man benötigt eine Zahl die nicht doppelt vorkommen darf sollte man auf jeden Fall einen Generator verwenden. Die Frage ist nur wann und wie man ihn erzeugt. Sofort wenn man einen neuen Datensatz anlegt oder erst wenn man ihn speichert. Ob man SELECT verwendet oder das GeneratorField von TIBQuery ist dabei auch noch egal.

ciao :hi:

urs.liska 9. Feb 2005 08:22

Re: [Interbase] Generatorwert zurücksetzen?
 
@Quake
Ich würde sagen: gamOnPost, wenn man den Primärschlüssel nicht schon vorher braucht (z.B für Detaildaten).

Für die Frage der lückenlosen Nummernfolge gibt es fertige Methoden (bitte nicht fragen wo und wie, ich weiß nur, dass es so was gibt; ich glaube, bei den Docs von ibphoenix oder ibobjects habe ich mal was gesehen).
Urs

Quake 9. Feb 2005 11:19

Re: [Interbase] Generatorwert zurücksetzen?
 
Ja genau das meinte ich für DatensatzID gamOnNewRecord und für RechnungsNr etc. gamOnPost. Die Details werden dann mit der DatensatzID verknüpft.

DelphiDeveloper 10. Feb 2005 01:45

Re: [Interbase] Generatorwert zurücksetzen?
 
Zitat:

Ja genau das meinte ich für DatensatzID gamOnNewRecord und für RechnungsNr etc. gamOnPost. Die Details werden dann mit der DatensatzID verknüpft.
Die RechNr bei OnPost zu generieren minimiert zwar das Problem aber eine lückenlose Sequenz von RechNr kriegt man dann auch noch nicht hin. Hat man irrtümich gepostet dann ist die Rechnr schon generiert und das löschen der Rechnung bringt "Löscher" in der Sequenz.

Ich würde mir für eindeutige Sequenzen sowas bauen:

Eine Tabelle mit einem Nummernkreis hier nur eine Zeile
ID NEXTNUMBER
1 4711

Eine Tabelle Nummernpool mit verwaisten Rechnr


Das ganze arbeitet dann wie folgt

hier als Pseudoalgo

exklusiver Zugriff auf Tabelle Nummernkreis anfordern (Lock)
wenn gesperrt warte...
schaue im Numernpool ob noch verwaiste Nr vorliegen
wenn ja hole satz aus nummernpool und loesch ihn dort -> fertig
wenn nix im Nummernpool
hole NEXTNumber aus Nummernkreis, incrementiere um 1 NextNumber in Nummernkreis
exklusiver Zugriff auf Tabelle zureucksetzen (unlock).

Quake 10. Feb 2005 07:52

Re: [Interbase] Generatorwert zurücksetzen?
 
Rechnungen dürfen nicht gelöscht werden. Wenn dann storniert man sie, d.h. man hat z.B. ein boolsches Feld STORNIERT das man auf true setzt. Deswegen entstehen erst garkeine Lücken.
Mit deiner Methode würdest du ja auch unter Umständen hinbekommen, daß du Rechnungs-Nr. von Heute zwischen die von vor 10 Jahren packst weil da zufällig eine gelöscht wurde. Das ist nicht Sinn der sache.

ciao :wink:

DelphiDeveloper 10. Feb 2005 10:04

Re: [Interbase] Generatorwert zurücksetzen?
 
Rechnungen löschen!
Es ist in vielen Unternehmen so, dass Rechnungen nach der Erstellung gelöscht oder geändert werden.

Solange Rechnungen noch nicht verschickt sind, spricht nichts dagegen sie auch wieder zu löschen und dann gehen bei mir die Nr auch wider in diesen besagten Nummernpool.
Das ist sehr praktikabel.

Eine Stornierung samt Gutschrift kommt erst zum tragen wenn wam dem Debitor die Rechnung tatsaechlich zugestellt hat.

mfg
DD

Quake 10. Feb 2005 10:41

Re: [Interbase] Generatorwert zurücksetzen?
 
Und wenn du eine Rechnung von vor ein paar Jahren löschst?

DelphiDeveloper 10. Feb 2005 10:47

Re: [Interbase] Generatorwert zurücksetzen?
 
wenn ne rechnung verschickt ist, hat sie den status dass sie nicht mehr loeschbar ist.

Quake 10. Feb 2005 12:20

Re: [Interbase] Generatorwert zurücksetzen?
 
Bei Datenbanken mit vielen Usern und vielen Zugriffen geht das locken und unlocken ganz schön auf die Performanz, da habe ich lieber ein paar stornierte Rechnungen in der Tabelle stehen. Aber soll nun auch gut sein zu diesem Thema, soll jeder so machen wie er es für besser erachtet.

ciao :cheers:

plautzer 11. Feb 2005 20:29

Re: [Interbase] Generatorwert zurücksetzen?
 
HI,

danke für eure zahlreichen Überlegungen.
Ich habe es jetzt so gelöst, dass man einen neuen datensatz anlegen will, der Generator abgefragt wird, manuell um eins erhöht und dann in das Feld eingefügt wird (damit die id sichtbar ist).
Erst wenn man auf speichern klickt wird die ID automatisch generiert( um 1 erhöht) und die restlichen Datensätze gespeichert.
Ich denke, das ist ne gute lösung, da der Generatorwert nicht angerührt wird und er die ID automatisch generiert, somit können keinen doppelten datensätze entstehen.

Plautzer

lume96 11. Feb 2005 21:23

Re: [Interbase] Generatorwert zurücksetzen?
 
Zitat:

Zitat von plautzer
HI,
Ich habe es jetzt so gelöst, dass man einen neuen datensatz anlegen will, der Generator abgefragt wird, manuell um eins erhöht und dann in das Feld eingefügt wird (damit die id sichtbar ist).
Erst wenn man auf speichern klickt wird die ID automatisch generiert( um 1 erhöht) und die restlichen Datensätze gespeichert.
Ich denke, das ist ne gute lösung, da der Generatorwert nicht angerührt wird und er die ID automatisch generiert, somit können keinen doppelten datensätze entstehen.
Plautzer

Hi,
dabei kannst Du aber nicht sicherstellen, dass die angezeigte ID auch im Endeffekt die ID des Records ist, ausser Du bist Dir sicher, dass immer nur eine Instanz/ein User auf die DB Zugriff hat. Sonst kann Folgendes passieren :
Instanz 1 fragt 'ne ID ab und kriegt 23 zurück
Instanz 2 fragt 'ne ID ab und kriegt auch 23 zurück

Instanz 1 speichert denn Record unter 23 (der Generator ist jetzt auf 24)
Instanz 2 speichert somit mit der ID 24 (obwohl vorher 23 angezeigt wurde).

Ist für den User noch unverständlicher, wenn Du ne Falsche ID anzeigst; dann doch besser vorher gar keine ID anzeigen.

Die am Anfang erfragte ID kannst Du sowieso nicht weiterverwenden, da sie nicht "sicher" ist.

Wie ich schon oben geschrieben habe, würde ich die ID erst beim POST generieren. Wo liegt da das Problem ?

Tschüss,
Lutz

Marcel Gascoyne 14. Feb 2005 10:23

Re: [Interbase] Generatorwert zurücksetzen?
 
Zitat:

Zitat von DelphiDeveloper
exklusiver Zugriff auf Tabelle Nummernkreis anfordern (Lock)
wenn gesperrt warte...
schaue im Numernpool ob noch verwaiste Nr vorliegen
wenn ja hole satz aus nummernpool und loesch ihn dort -> fertig
wenn nix im Nummernpool
hole NEXTNumber aus Nummernkreis, incrementiere um 1 NextNumber in Nummernkreis
exklusiver Zugriff auf Tabelle zureucksetzen (unlock).

Warum nicht einfach so ohne Locking:

SQL-Code:
select NextNumber
from Nummernkreis
where id = 1

update Nummernkreis
set NextNumber = (ergebnis von obigen select + 1)
where nextnumber = (ergebnis von obigen select)
Wenn der Update Part nicht klappt wurde zwischenzeitlich bereits eine Änderung gemacht und man versucht es komplett noch einmal bis es halt klappt.

Gruß,
Marcel

Quake 15. Feb 2005 07:36

Re: [Interbase] Generatorwert zurücksetzen?
 
@Marcel :gruebel:

Marcel Gascoyne 15. Feb 2005 07:44

Re: [Interbase] Generatorwert zurücksetzen?
 
Ganz einfach: Per Select wird die aktuelle Belegnummer ermittelt. Nun wird diese um eins erhöht und per Update gespeichert. Durch Angabe der alten Belegnummer in der Where-Clause wird sichergestellt das nur aktualisiert wird wenn zwischenzeitlich kein anderer eine neue Belegnummer erzeugt hat.

Gruß,
Marcel

plautzer 15. Feb 2005 17:24

Re: [Interbase] Generatorwert zurücksetzen?
 
Zitat:

Zitat von Marcel Gascoyne
... diese um eins erhöht und per Update gespeichert. Durch Angabe der alten Belegnummer in der Where-Clause wird sichergestellt das nur aktualisiert wird wenn zwischenzeitlich kein anderer eine neue Belegnummer erzeugt hat.

Per Update?

wo soll das denn gespeichert werden? Man müsste erst einmal einen Datensatz erstellen (insert) bevor man ihn bearbeiten kann.

Mein Prog. ist nur für einen Benutzer, also sollte das ganze ohne weiteres funzen.

thx Leute,


Plautzer

Quake 16. Feb 2005 09:07

Re: Interbase Generatorwert zurücksetzen?
 
@Marcel: Wozu gibt es denn generatoren, die erhöhen ihren Wert automatisch um 1. Und das Problem, wenn mehrere Benuter gleichzeitig auf die DB zugreifen, ist immernoch nicht gelöst. Wenn dann müßte auch die Tabelle Nummernpool geblockt werden. Bei 2 Benutern mag das noch gehen, aber lass mal 100 Benutzer an der DB arbeiten, dann viel Spaß beim Kaffee trinken. Und bei dieser Methode muss blockiert werden, damit nicht 2 Benutzer gleichzeitig den gleichen Wert abrufen. Dann würden Nummern doppelt vergeben. Wie lange soll den das "Rumgeupdate wenns nicht klappt" in großen DBs dauern?


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:43 Uhr.

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