Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Trigger verhindet löschen eines Datensatzes (https://www.delphipraxis.net/54243-trigger-verhindet-loeschen-eines-datensatzes.html)

VizeTE 30. Sep 2005 13:25

Datenbank: Interbase • Version: 4 • Zugriff über: BDE

Trigger verhindet löschen eines Datensatzes
 
Hallo zusammen,

ich habe ein Problem mit einem Trigger.

Ich füge einen neuen Datensatz in eine Tabelle ein. Auf dem Ereignis "Before Update" liegt ein Trigger der den DS um Datum und Uhrzeit ergänzt.
Wenn ich im Anschluß diesen DS wieder löschen will bekomme ich folgende Fehlermeldung:

Datensatz kann nicht gesperrt werden, da der Datensatz von einem anderen Benutzer geändert wurde.

Wenn ich den Trigger deaktiviere funktionierts problemlos. Ich möchte aber nur ungern auf die Funktionalität des Triggers verzichten.

Eingentlich macht das in meinen Augen auch nicht so richtig Sinn, oder wird "Before Update" auch beim hinzufügen eines DS ausgeführt?
Wenn ich einen Trigger auf "Before Insert" setze funktioniert das alles auch problemlos. Ich möchte aber das Datum auch beim ändern der Daten aktualisiert haben.

Hat jemand einen Tip für mich?

Vielen Dank - Daniel

jensw_2000 30. Sep 2005 13:44

Re: Trigger verhindet löschen eines Datensatzes
 
Interbase kenne ich nich so gut.
Gibt es bei IB in den Triggern auch die temporärern Tabellen INSERTED und DELETED, so wie das bei MSSQL der Fall ist?

Falls ja, könntest du es wie folgt lösen:

SQL-Code:
DECLARE @DelCount INT

SELECT @DelCount=COUNT(*) FROM DELETED

IF (@DelCount IS NULL) OR (@DelCount = 0)
BEGIN
  -- es wurde kein Datansatz gelöscht
  ... hier den Trigger Code ausführen
END
ELSE BEGIN
  -- es wurde min. ein Datansatz gelöscht
  ... Trigger Code wird nicht ausgeführt
END
Schöne Grüße,
Jens
:hi:

VizeTE 30. Sep 2005 13:51

Re: Trigger verhindet löschen eines Datensatzes
 
Solche temporären Tabellen sind mir nicht bekannt.

Ich habe inzwischen eine Möglichkeit gefunden das Problem zu umgehen. Bisher habe ich direkt in der Abfrage den Datensatz mit "Query.Delete" gelöscht. So kam es zu oben beschriebenen Fehler.
Jetzt habe ich eine weitere "Delete FROM..." Abfrage eingesetzt und es funktioniert erst einmal.
Aber so richtig schön finde ich das nicht.

Würde micht sehr freuen wenn mir da noch jemand auf die Sprünge helfen könnte.

Gruss

Hansa 30. Sep 2005 15:41

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von VizeTE
..Ich füge einen neuen Datensatz in eine Tabelle ein. Auf dem Ereignis "Before Update" liegt ein Trigger der den DS um Datum und Uhrzeit ergänzt...

Warum wird ein Update-Trigger verwendet beim Insert ? :shock: Du hast doch bestimmt einen Trigger, um die ID hochzuzählen. Also ist das doch die beste Stelle, das Datum gleich mit abzuspeichern.

VizeTE 30. Sep 2005 17:13

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von Hansa
Warum wird ein Update-Trigger verwendet beim Insert ?

Nein, es wird natürlich beim Insert nicht der Update-Trigger verwendet sondern ein anderer. Aber der Inhalt des Triggers ist der gleiche. Ich wollte damit nur verdeutlichen, daß es am Trigger selbst nicht liegen sollte. Da wird nur folgender Code ausgeführt:
Delphi-Quellcode:
new.Modified = 'now';
Zitat:

Zitat von Hansa
Du hast doch bestimmt einen Trigger, um die ID hochzuzählen.

Für diese Tabelle gibt es ausnahmsweise keinen Trigger der eine Id hochzählt. Aber das sollte ja auch keine Rolle spielen. Auf diese Tabelle gibt es nur 2 Trigger. Einen für "Before Insert" und einen für "Before Update". Damit ich Probleme durch 2 Trigger ausschließen kann habe ich das Szenario mit jeweils einen aktiven und einen deaktivierten Trigger durchgespielt.
Den Fehler gibt es nur beim "Before Update"-Trigger.

Ohne großes Hintergrundwissen würde ich vermuten das die Datenbank den Trigger als einen anderen Benutzer/eine andere Session laufen läßt. Aber das macht ja keinen richtigen Sinn. Wenn ich die DB eine Transaction ausführen lasse dann weiß sie ja auch das ein Trigger zu dieser Transaction gehört. Also müßte es doch in der gleichen Session passieren?!

Hansa 30. Sep 2005 17:24

Re: Trigger verhindet löschen eines Datensatzes
 
Habe in der DB nachgeguckt : alle Felder, die durch ein Insert automatisch beeinflußt werden, kriegen diese Sachen mit einem BI-Trigger verpaßt. Default Werte usw. Soll bei einem UPDATE noch was gemacht werden, so erledigt das ein AFTER UPDATE Trigger, kein BEFORE ! Womit wird das Ganze überhaupt getestet ? Ist das wirklich noch IB 4 ?

Jelly 30. Sep 2005 17:42

Re: Trigger verhindet löschen eines Datensatzes
 
Kannst du nicht mit Default Werten arbeiten, die du gleich beim Erstellen der Tabelle angibst.

Hansa 30. Sep 2005 18:21

Re: Trigger verhindet löschen eines Datensatzes
 
Siehe dieses Beispiel hier. Beim Erstellen der Tabelle kann ich doch noch nicht wissen, daß ich in 1 Stunde um 20:19:55,4 einen neuen Datensatz anlege ! Der Trigger überwacht das ganze deshalb und merkt sich, daß da die Zeit festgehalten werden muß, auch wenn ichs vergesse. 8)

VizeTE 1. Okt 2005 11:15

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von Hansa
Soll bei einem UPDATE noch was gemacht werden, so erledigt das ein AFTER UPDATE Trigger, kein BEFORE ! Womit wird das Ganze überhaupt getestet ? Ist das wirklich noch IB 4 ?

Das "After Update" habe ich auch schon probiert. Da stand danach leider nichts in der DB - naja was heißt nichts, nicht das was der Trigger schreiben sollte. Zur Sicherheit werde ich das aber nochmal probieren.
Zum Test: In die Datenbank habe ich mit einen Delphi-Programm und den BDE-Komponenten geschrieben. Geprüft was in der DB drin steht habe ich mit dem DB-Explorer.
Ja, das ist wirklich noch IB4, leider ;)

MagicAndre1981 1. Okt 2005 11:30

Re: Trigger verhindet löschen eines Datensatzes
 
Warum muss es unbedingt der IB4 sein? Schonmal über ein Wechsel auf eine höhere Version nachgedacht?

VizeTE 1. Okt 2005 19:03

Re: Trigger verhindet löschen eines Datensatzes
 
mmm...es ist leider nicht meine Entscheidung welche Datenbank eingesetzt wird also werde ich wohl noch eine Weile an IB4 festhalten (müssen). :?

MagicAndre1981 1. Okt 2005 19:06

Re: Trigger verhindet löschen eines Datensatzes
 
Dann pack den Code zum Datum einfügen in das BeforePost-Event der BDE-Komponente, dann brauchst du keinen Trigger. Ist nicht ganz sauber, aber probier das mal.

André

VizeTE 4. Okt 2005 16:38

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von MagicAndre1981
Dann pack den Code zum Datum einfügen in das BeforePost-Event der BDE-Komponente, dann brauchst du keinen Trigger. Ist nicht ganz sauber, aber probier das mal.

Theoretisch sollte das gehen aber das ist leider auch noch nicht was ich suche da ich gern die Serverzeit in dem Datumsfeld hätte und nicht die Zeit auf dem Client.

Jelly 4. Okt 2005 16:47

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von Hansa
Siehe dieses Beispiel hier. Beim Erstellen der Tabelle kann ich doch noch nicht wissen, daß ich in 1 Stunde um 20:19:55,4 einen neuen Datensatz anlege ! Der Trigger überwacht das ganze deshalb und merkt sich, daß da die Zeit festgehalten werden muß, auch wenn ichs vergesse. 8)

Jetzt versteh ich erst was du damit meintest. Hab mich vielleicht schlecht ausgedrückt. Aber du kannst auch als default Wert das aktuelle Datum nehmen, zumindest unter dem MSSQL Server kein Problem:
SQL-Code:
create table Daten (
ID int,
Datum datetime null default getdate())
go
Muss Dir jetzt nur noch die Funktion aus dem IB holen, die dir das aktuelle Datum liefert.

VizeTE 4. Okt 2005 16:50

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von Jelly
Aber du kannst auch als default Wert das aktuelle Datum nehmen, zumindest unter dem MSSQL Server kein Problem

Ich bezweifle, dass das Interbase kann. Aber selbst wenn benötige ich diese Funktion ja auch nach dem ändern des DS. Da hilft der default-Wert leider nicht weiter.

Hansa 4. Okt 2005 17:18

Re: Trigger verhindet löschen eines Datensatzes
 
@Viez, bist du immer noch dran die DB zu zerhackstückeln ? :shock:

SQL-Code:
/******************************************************************************/
/****              Generated by IBExpert 04.10.2005 18:10:28               ****/
/******************************************************************************/

SET SQL DIALECT 3;

SET NAMES ISO8859_1;

SET TERM ^ ;

CREATE TRIGGER TABLE1_AUO FOR TABLE1
ACTIVE AFTER UPDATE POSITION 0
as
begin
  update TABLE1 set
    LETZTEAENDERUNG = current_timestamp
  where (ID = old.ID) and ((LETZTEAENDERUNG is null) or
        (LETZTEAENDERUNG <> current_timestamp));
end
^

SET TERM ; ^
Der Trigger protokolliert sekundengenau, wann zuletzt an der DB an diesem einen betroffenen Datensatz etwas geändert wurde. Es wäre ein leichtes, dabei noch festzuhalten welcher User es war usw. Wo liegt das Problem ? Natürlich kann man das nicht schon beim Erzeugen der Table machen und deshalb sind die Default-Werte fehl am Platze.

VizeTE 5. Okt 2005 09:36

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von Hansa
Der Trigger protokolliert sekundengenau, wann zuletzt an der DB an diesem einen betroffenen Datensatz etwas geändert wurde. Es wäre ein leichtes, dabei noch festzuhalten welcher User es war usw. Wo liegt das Problem ?

Das funktioniert prinzipiell, ja. Das Problem liegt aber darin wenn ich diesen DS, nachdem "Post" aufgerufen wurde, nochmal ändere. Dann bekomme ich folgende Fehlermeldung: (wie Eingangs beschrieben)

Datensatz kann nicht gesperrt werden, da der Datensatz von einen anderen Benutzter geändert wurde.
(EDBEngineError)


Die einzige Erklärung die ich mir denken kann ist, daß der Trigger als ein anderer User läuft. Aber so richtig kann ich das auch nicht glauben. Wenn ich ein Rollback mache weiß die DB ja auch welche Trigger dazugehören.

dfried 5. Okt 2005 10:44

Re: Trigger verhindet löschen eines Datensatzes
 
Das Problem ist doch einfach, dass die BDE vor dem löschen nochmal nachschaut, ob sich der Datensatz inzwischen geändert hat. Und da der Trigger den Datensatz nochmal geändert hat meint die BDE eben es war noch ein anderer Benutzer an dem Datensatz dran.

Du kannst jetzt folgendes machen:

1. in deiner TTable oder TQuery den UpdateMode auf upWhereKeyOnly setzen (vorausgesetzt du hast einen Primary Key)

2. nach dem Insert/Update des Datensatzes gleich einen Refresh auf diesen Datensatz machen, das wäre eh die bessere Lösung, dann siehst du die vom Trigger generierten Werte auch gleich auf dem Client

Danach dürfte dem Löschen nix mehr im Weg stehen.

Gruß
Daniel

VizeTE 5. Okt 2005 11:20

Re: Trigger verhindet löschen eines Datensatzes
 
Hallo dfried.

Die erste Lösung funktioniert schon mal. Danke.
Wenn ich den Update-Modus "upWhereKeyOnly" verwende muß ich dann noch irgendwas beachten? Soweit ich die Hilfe verstande habe bekomme ich keine Probleme solange ich den Key nicht ändere. Gibts da noch mehr Stolpersteine?

Die zweite Lösung scheint mir aber auch vernünftiger. Ich verwende ein TQuery. Wie kann ich da einen Primary Key verwenden? Die zu Grunde liegende Tabelle besitzt einen Primary Key aber wie ich den in die Abfrage bekomme weiß nicht.

Jelly 5. Okt 2005 11:23

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von VizeTE
Die zweite Lösung scheint mir aber auch vernünftiger. Ich verwende ein TQuery. Wie kann ich da einen Primary Key verwenden? Die zu Grunde liegende Tabelle besitzt einen Primary Key aber wie ich den in die Abfrage bekomme weiß nicht.

Was hat dein Primary Key mit Delphi zu tun :gruebel: Ich versteh dein Problem nicht.

VizeTE 5. Okt 2005 11:29

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von Jelly
Was hat dein Primary Key mit Delphi zu tun :gruebel: Ich versteh dein Problem nicht.

dfried hat ein Refresh vorgeschlagen. Wenn ich aber myQuery.Refresh aufrufen bekomme ich die Fehlermeldung:

Operation wird nicht unterstützt - Tabelle ist nicht eindeutig indiziert. (EDBEngineError)

Jelly 5. Okt 2005 11:33

Re: Trigger verhindet löschen eines Datensatzes
 
Das typische nicht vermeidbare Refresh Problem also.

Leider kommst du nicht um ein close, open herum. Dadurch allerdings stehst du nicht mehr auf dem gewünschten Record, d.h. du musst mit Locate wieder dorthin springen.

VizeTE 5. Okt 2005 12:08

Re: Trigger verhindet löschen eines Datensatzes
 
Das habe ich schon befürchtet.
Das ist bei großen Datenmengen aber recht nervig, daher hatte ich gehofft das es eine bessere Lösung gibt.

Ich werde mal ein wenig mit der Methode UpdateMode auf upWhereKeyOnly setzen herumspielen. Auf den ersten Blick schien das ganz gut zu funktionieren.

dfried 5. Okt 2005 12:12

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von VizeTE
Das habe ich schon befürchtet.
Das ist bei großen Datenmengen aber recht nervig, daher hatte ich gehofft das es eine bessere Lösung gibt.

Das stimmt allerdings, ist halt ein Problem von Interbase und der BDE :-(

Zitat:

Zitat von VizeTE
Ich werde mal ein wenig mit der Methode UpdateMode auf upWhereKeyOnly setzen herumspielen. Auf den ersten Blick schien das ganz gut zu funktionieren.

Du musst nur beachten, dass halt mit dieser Einstellung auch bei "normalen" updates nicht mehr alle Felder auf evtl. Änderungen durch andere User geprüft werden d.h. im Multiuserbetrieb kann es unter Umständen dann dazu führen, dass Benutzer A den Datensatz ändert während Benutzer B auch schon dabei ist. Derjenige der zuletzt auf "speichern" drückt hat halt gewonnen. :)

Ansonsten gibt es eigentlich keine (mir bekannten) Probleme mit dem umsetzen des UpdateMode.

Gruß
Daniel

VizeTE 5. Okt 2005 12:43

Re: Trigger verhindet löschen eines Datensatzes
 
Zitat:

Zitat von dfried
Du musst nur beachten, dass halt mit dieser Einstellung auch bei "normalen" updates nicht mehr alle Felder auf evtl. Änderungen durch andere User geprüft werden d.h. im Multiuserbetrieb kann es unter Umständen dann dazu führen, dass Benutzer A den Datensatz ändert während Benutzer B auch schon dabei ist. Derjenige der zuletzt auf "speichern" drückt hat halt gewonnen. :)

Ahh...dann hatte ich das doch noch nicht ganz verstanden. Aber ich denke mit dieser Einschränkung kann ich leben. Bei dieser Tabelle sollten eingentlich nur eine Person zur gleichen Zeit arbeiten. Die Daten sind auch nicht sooo kritisch falls da mal was "falsch" gespeichert wird.

Danke! :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:42 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-2025 by Thomas Breitkreuz