[Gelöst] Kein Rollback bei Error nach EventSubscriber

23. April 2020 16:19

Hallo zusammen,

ich plage mich mit einem sehr seltsamen Phänomen herum.

Ausgangslage:
Ich habe eine Funktionalität ("Synchronisation"), welche das Event OnAfterOnDatabaseModify der Codeunit 1 abonniert.
Diese schaut in einer Tabelle nach, ob die Daten der Herkunftstabelle (die den Modify ausgelöst hat) in andere Tabellen synchronisiert werden sollen.
Die ganze Funktion ist RecRef- und FieldRef-basiert.

Grundsätzlich funktioniert diese Synchronisation hervorragend.

Wenn in einer der Zieltabellen eine Änderung nicht (mehr) erlaubt ist (weil z. B. ein bestimmter Status erreicht/überschritten ist), dann bricht die Synchronisation mit der entsprechenden Fehlermeldung ab und die Änderungen in den Zieltabellen werden zusammen mit den Änderung in der Herkunftstabelle durch den Rollback rückgängig gemacht.
Bis hierhin alles wie gewünscht.

Problem:
Leider kommt es bei einigen wenigen Fällen dazu, dass zwar die Änderungen in den Zieltabellen zurückgedreht werden, die Änderung in der Herkunftstabelle jedoch gespeichert bleibt.
Es erscheint in dem Fenster der Herkunftstabelle (z. B. Verkaufauftrag) die entsprechende Fehlermeldung und der eingegebene Wert in dem Feld wird nicht gespeichert.
Wenn der Anwender jetzt F5 zum Aktualisieren drückt, damit die Fehlermeldung verschwindet, dann bleibt der (unzulässige) neue Wert in dem Feld aber stehen.

Bei anderen Feldern derselben Herkunftstabelle tritt dieses Verhalten jedoch nicht auf.
Dort kann der Feldwert nach einer Fehlermeldung nicht mit dem "F5-Trick" untergejubelt werden.

Bisherige Recherche:
In dem betroffenen Feld gibt es keinen Programmcode im OnValidate-Trigger und während der gesamten Synchronisation wird auch kein COMMIT ausgeführt.
Ebenso gibt es auch keine EventSubscriber, die direkt auf das OnAfterValidate-Event dieses Feldes gehen.

EventSubscriber auf das OnAfterModify-Event der Herkunftstabelle oder gar auf OnAfterOnDatabaseModify habe ich ebenfalls untersucht und keine COMMITS gefunden.

Frage:
Was könnte der Grund für dieses "unerwartete Programmverhalten" sein, und wie kann man es beheben?

Zur Info:
Datenbank: NAVDE10.00.16177 (CU 09)
Runtime: NAV 10.00.18609 (CU11)



In einem anderen, jedoch ähnlichem Problem konnte ich herausfinden, dass eine Prüfung in dem EventSubscriber Table37-OnAfterModify implementiert war.
Dieses Event wird jedoch nach der Datenbank-Schreibtransaktion ausgeführt, daher wird für alles vor diesem Event kein Rollback mehr durchgeführt.
Durch Verschiebung der Prüfung von OnAfterModify auf das Feld-Event OnAfterValidate funktionierte der Rollback dann hervorragend.

Diese Erkenntnis bringt mir in meinem o. g. Problem jedoch nichts, da ich ja vom OnAfterOnDatabaseModify der Codeunit 1 aus starte.

Re: Kein Rollback bei Error nach EventSubscriber

23. April 2020 16:34

Beispiel, bei dem der vollständige Rollback funktioniert:
Nach der Belegfreigabe des Verkaufsauftrags werden für bestimmte Verkaufszeilen sogenannte "Transportanforderungen" erstellt.
Solange diese Transportanforderungen noch nicht disponiert sind (Tourstatus::Disponiert), können in der Herkunftsbelegzeile alle Daten nach belieben geändert werden.
Diese Änderungen werden über die Synchronisation in die Transportanforderung(en) übertragen.
Ist die Transportanforderung disponiert, dann dürfen "dispo-relevante" Felder (wie z. B. Artikelnr., Lieferdatum, Menge, ...) nicht mehr geändert werden.
Diese Prüfung findet in dem OnValidate-Trigger der entsprechenden Felder in der Tabelle "Transportanforderung" statt.
Läuft die Synchronisation in einem dieser Trigger auf einen Fehler, so führt NAV einen vollständigen Rollback durch und auch der Wert in der Verkaufszeile wird wieder zurückgesetzt.

Beispiel, bei dem der Rollback nicht vollständig funktioniert:
Nach der Belegfreigabe des Verkaufsauftrags werden sogenannte "Arbeitsaufträge" für verschiedene Abteilungen erstellt, die an der Bearbeitung dieses Auftrags beteiligt sind (z. B. Montage, Lackiererei, Elektroprüfung, ...).
Für jede Abteilung wird ein eigener Arbeitsauftrag angelegt.
Solange noch keiner dieser Arbeitsaufträge in Bearbeitung ist, können in der Herkunftsbelegzeile alle Daten nach belieben geändert werden.
Diese Änderungen werden über die Synchronisation in die Arbeitsauftragszeilen übertragen.
Sobald auch nur ein einziger Arbeitsauftrag in Bearbeitung ist (Status::In Bearbeitung), dürfen "arbeitsauftrags-relevante" Felder (wie z. B. Artikelnr., Lieferdatum, Menge, ...) nicht mehr geändert werden.
Diese Prüfung findet in dem OnValidate-Trigger der entsprechenden Felder in der Tabelle "Arbeitsauftragszeile" statt.
Läuft die Synchronisation in einem dieser Trigger auf einen Fehler, so werden alle synchronisierten Daten in allen Arbeitsauftragszeilen wieder zurückgesetzt, jedoch kann der unzulässige Wert in der Verkaufszeile mit F5 trotzdem gespeichert werden.

Re: Kein Rollback bei Error nach EventSubscriber

23. April 2020 16:54

Gibt es irgendwelche Try-Functions?

Re: Kein Rollback bei Error nach EventSubscriber

23. April 2020 17:14

Spannend. Ich habe das Verhalten in einer kompletten Eigenentwicklung auch schon gesehen mit F5 ohne commit. Konnte es aber noch nicht wieder reproduzieren. Allerdings in BC 15. Leider kann ich keine weitere Hilfe liefern...

Re: Kein Rollback bei Error nach EventSubscriber

24. April 2020 11:00

m_schneider hat geschrieben:Gibt es irgendwelche Try-Functions?

Vielen Dank für diesen sehr wertvollen Hinweis.
Bisher haben wir keine TryFunctions erstellt oder verwendet.
Ich habe mit dem Object Manager den kompletten Programmcode nach [TryFunction] absuchen lassen, aber keiner der Treffer trifft auf dieses Problem zu, da sie weder direkt noch indirekt angesprochen werden.

Wir haben auch schon alle Objekte der Datenbank kompiliert, die Serveranwendungsobjekte neu erstellen lassen und die ServiceTiers gestoppt und neu gestartet, um sicherzustellen, dass die Metadaten korrekt sind und von den ServiceTiers keine veralteten Metadaten verwendet werden, aber auch das brachte uns bisher nicht zum Erfolg.

Ich bin also weiterhin für jeden noch so blöd klingenden Vorschlag dankbar.

Gibt es in den Microsoft-Datenbanken (Knowledge Base & Co., PartnerSource, ...) irgendwelche direkten oder indirekten Release-Notes, dass durch ein höheres CU ein solches Fehlverhalten behoben wurde?
(Nochmal zur Info: Unsere Laufzeitumgebung hat die Version 10.00.18609 alias NAV2017 CU11.)

Re: Kein Rollback bei Error nach EventSubscriber

24. April 2020 11:25

Timo Lässer hat geschrieben:Ich habe eine Funktionalität ("Synchronisation"), welche das Event OnAfterOnDatabaseModify der Codeunit 1 abonniert

Das könnte schon die Wurzel des Übels sein. Mittlerweile wurden dieses Event ja verlegt, es ist jetzt in Codeunit 49.
New system events replace Codeunit 1 in Business Central October’18 release
Es steht in dem obigen Artikel dazu die Warnung
You also should not directly subscribe to the events in these codeunits either.

Leider ohne Begründung, weshalb und wieso. Begründung s.u.
Aber das würde ich hier dann thematisieren.
https://github.com/Microsoft/ALAppExtensions
Das betrifft AL ja gleichermaßen.

Re: Kein Rollback bei Error nach EventSubscriber

24. April 2020 13:26

Ich habe eine Funktionalität ("Synchronisation"), welche das Event OnAfterOnDatabaseModify der Codeunit 1 abonniert

Interessant wäre auszuprobieren, den Modify für die betroffene Tabelle nicht über den globalen Trigger in der CU1 sondern direkt den OnBeforeModifyEvent der Tabelle zu abonieren. Vlt. gibt es ein unterschiedliches Verhalten mit dem Rollback je nachdem ob OnBefore oder OnAfter.

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 08:28

Kowa hat geschrieben:
Timo Lässer hat geschrieben:Ich habe eine Funktionalität ("Synchronisation"), welche das Event OnAfterOnDatabaseModify der Codeunit 1 abonniert
Das könnte schon die Wurzel des Übels sein. Mittlerweile wurden dieses Event ja verlegt, es ist jetzt in Codeunit 49.
Unsere Datenbank ist noch Version 2017 (10.00), da gibt es die neuen Codeunits noch nicht. :wink:

Jupiter hat geschrieben:Interessant wäre auszuprobieren, den Modify für die betroffene Tabelle nicht über den globalen Trigger in der CU1 sondern direkt den OnBeforeModifyEvent der Tabelle zu abonieren.
Der OnBeforeModify scheidet aus zwei Gründen aus:
1. Darf die Synchronisation nicht starten, solange der Modify in der Herkunftstabelle nicht tatsächlich ausgeführt wird, da ja die aktuellsten Daten für die Synchronisation benötigt werden.
2. Müsste ich dazu für jede Tabelle einzeln das Tabellen-Event abonnieren.

Sobald jemand auf die Idee kommt, dass z. B. die Daten zwischen Mitarbeiter (T5200) und Ressourcen (T156) synchronisiert werden sollen, müssten wir erstmal die entsprechenden Events programmieren.

Daher fragte ich ja
Timo Lässer hat geschrieben:Gibt es in den Microsoft-Datenbanken (Knowledge Base & Co., PartnerSource, ...) irgendwelche direkten oder indirekten Release-Notes, dass durch ein höheres CU ein solches Fehlverhalten behoben wurde?
(Nochmal zur Info: Unsere Laufzeitumgebung hat die Version 10.00.18609 alias NAV2017 CU11.)

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 08:50

Timo Lässer hat geschrieben:Unsere Datenbank ist noch Version 2017 (10.00), da gibt es die neuen Codeunits noch nicht. :wink:

Das ist mir schon klar, es ging ja auch nur um Events, die man nicht direkt abonnieren soll, egal wo die liegen. OnAfterOnDatabaseModify gehört da dazu.

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 10:19

Ich stehe gerade etwas auf dem Schlauch. :roll:
Wie soll ich denn sonst OnDatabaseModify der Codeunit 1 abonnieren, wenn nicht über das von Microsoft bereitgestellte Event OnAfterOnDatabaseModify?
In 2017 liegt dieses Event nunmal noch in der Codeunit 1, in späteren Versionen halt woanders.

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 10:39

Timo Lässer hat geschrieben:Wie soll ich denn sonst OnDatabaseModify der Codeunit 1 abonnieren, wenn nicht über das von Microsoft bereitgestellte Event OnAfterOnDatabaseModify?

Eigentlich an die Integration Events (die sich häufiger je nach Version mal ändern können), die diese abonniert haben.
Instead you should subscribe to one of the integration events which now reside next to the business logic. The reason for this is to ensure the correct ordering of events and to provide before/after events where appropriate.

Die Möglichkeit des direkten Abonnierens soll ohnehin bald abgeklemmt werden (was wiederum die gesuchte Begründung sein dürfte :wink: )
While technically possible as of now, we will block this in the future which would be a breaking change for you.

Event Types

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 11:43

In 2017 gibt es leider noch keine andere Möglichkeit, auf OnDatabaseModify zu reagieren, als das Event OnAfterOnDatabaseModify der Codeunit 1 zu abonnieren.
Weder gibt es in 2017 die Codeunit 49, noch die Codeunit 2000000002.

Ich befürchte, dass ich wohl (oder übel) nicht darum komme, für die Fälle einer vorherigen Prüfung (die zu einem gewollten Abbruch führen darf) separate Funktionen zu schreiben, welche ich an Events der jeweiligen Herkunftstabelle binde.
Das gefällt mir natürlich überhaupt nicht, da es ja sein könnte, dass man die Geschäftsprozesse demnächst etwas umstellt, und dann bestimmte Feldänderungen weiterhin (oder bis zu einem höheren Status) erlaubt sind.
(Bei uns passen sich die Geschäftsprozesse sehr schnell an die aktuellen Marktbedingungen an.)

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 16:50

Timo Lässer hat geschrieben:...Ich befürchte, dass ich wohl (oder übel) nicht darum komme, für die Fälle einer vorherigen Prüfung (die zu einem gewollten Abbruch führen darf) separate Funktionen zu schreiben, welche ich an Events der jeweiligen Herkunftstabelle binde....

Die Frage wäre ja erstmal, funktioniert es, wenn du es so machst?

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 16:52

Timo Lässer hat geschrieben:[...]
Leider kommt es bei einigen wenigen Fällen dazu, dass zwar die Änderungen in den Zieltabellen zurückgedreht werden, die Änderung in der Herkunftstabelle jedoch gespeichert bleibt.
[...]nicht mehr geändert werden.
Diese Prüfung findet in dem OnValidate-Trigger der entsprechenden Felder in der Tabelle "Transportanforderung" statt.[...]


Hi Timo,

ich verstehe nicht ganz, warum die Zieltabelle schon beschrieben wird und warum sich die Prüfungen in den Validate-Triggern der Zieltabelle befinden. Wird denn in beide Richtungen synchronisiert?

Ich bin mir nicht so sicher ob das mit reinspielt, aber es ist leider so, dass Validateänderungen über RecordRefs von NAV nicht erkannt werden. Also ggf. vorhandene xRec.Feld <> Rec.Feld Prüfungen im Modify-Trigger einer Tabelle erkennen keinen Unterschied, wenn du ein Feld per FieldRef validierst.

Ich würde das ganze so machen:
OnAfterOnDatabaseModify oder auch OnAfterReleaseSalesDoc abonnieren.
Bei ersterem musst du auch OnAfterGetDatabaseTableTriggerSetup abonnieren und OnDatabaseModify auf TRUE setzen.

Jetzt hast du ja den RecRef mit der Änderung. Wenn RecRef deiner Herkunftstabelle entspricht, hol dir mit xRecRef.GET(RecRef.RECORDID) den ursprünglichen Datensatz sowie die Datensätze deiner Zieltabellen und prüfe ob die Feldrelevanten Änderungen (FldRef := RecRef.FIELD(FldNo); xFldRef := xRecRef.FIELD(FldNo);) synchronisiert werden dürfen. Wenn nicht, dann wirf den ERROR. Damit hat sich ja noch nichts in der Zieltabelle geändert.

Ich mache auf diese Art und Weise eine Prüfung, ob ein bestimmter Nutzer überhaupt Änderungen an einem Feld vornehmen darf (Extra Tabelle mit "Feldberechtigungen" vorhanden). Ich werfe hier auch ein ERROR, wenn User X das Feld Y einer Tabelle nicht ändern darf und wüsste nicht, dass man das mit F5 umgehen kann.

VG

Re: Kein Rollback bei Error nach EventSubscriber

27. April 2020 17:00

Hallo,

ob xRec gefüllt ist oder nicht hatte ich gerade irgendwo.

Das hier kennt ihr aber:

XRec.png


Gruß Fiddi
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Kein Rollback bei Error nach EventSubscriber

28. April 2020 09:31

m_schneider hat geschrieben:
Timo Lässer hat geschrieben:...Ich befürchte, dass ich wohl (oder übel) nicht darum komme, für die Fälle einer vorherigen Prüfung (die zu einem gewollten Abbruch führen darf) separate Funktionen zu schreiben, welche ich an Events der jeweiligen Herkunftstabelle binde....
Die Frage wäre ja erstmal, funktioniert es, wenn du es so machst?
Da wir - soweit es irgendwie technisch möglich ist - Standard-Trigger nur per Event-Abo erweitern, haben wir in unserer Datenbank unzählige Beispiele, bei denen es zuverlässig funktioniert.

vandyke hat geschrieben:ich verstehe nicht ganz, warum die Zieltabelle schon beschrieben wird und warum sich die Prüfungen in den Validate-Triggern der Zieltabelle befinden.
Die Prüfungen befinden sich dort, wo sie erforderlich sind, daher in dem Validate-Trigger der Zieltabelle.
Die "Synchronisation" weiß nicht, in welche Tabellen und Felder sie welche Herkunftsfeldwerte übertragen soll. Das erfährt sie erst wenn sie die Einrichtungstabelle(n) durchläuft.
Für jedes zu synchronisierende Feld wird natürlich abgefragt, ob SourceFieldRef.VALUE <> TargetFieldRef.VALUE ist, um unnötige Feldänderungen zu unterbinden.
Sind Source und Target unterschiedlich, wird geprüft, ob der Wert mit oder ohne VALIDATE übertragen werden soll.
Durch die Übertragung mit VALIDATE wird dann der OnValidate-Trigger des Zielfeldes ausgeführt.
Dieser prüft, ob der Status der Zieltabelle einen bestimmten Wert noch nicht erreicht bzw. überschritten hat.
Sollte der Status den bestimmten Wert erreicht oder überschritten haben, wird der OnValidate des Zielfeldes mit einem Error abgebrochen.

In fast allen Situationen funktioniert das auch zuverlässig und der Error löst einen Rollback aus, der sich bis zu dem Modify der Herkunftstabelle auswirkt und auch nicht mit einem anschließenden F5 ausgetrickst werden kann.
Nur bei diesem einen Feld in dieser einen Tabelle kann ich den (unzulässigen) Wert nach dem Error trotzdem durch F5 in dem Datensatz abspeichern.

vandyke hat geschrieben:Wird denn in beide Richtungen synchronisiert?
Es ist technisch denkbar, dass in beide Richtungen synchronisiert wird, jedoch ist durch entsprechende Programmierung sichergestellt, dass die Synchronisation nur von "Herkunftstabellennr." in die "Zieltabellennr." überträgt und in der Transaktion nicht noch die weiterführenden Synchronisationen (also von der Zieltabelle ausgehend) anstößt.

vandyke hat geschrieben:aber es ist leider so, dass Validateänderungen über RecordRefs von NAV nicht erkannt werden.
Das kann ich leider nicht bestätigen.
TargetFieldRef.VALIDATE(NewValue) funktioniert bei uns hervorragend zuverlässig. (Sonst würde ja auch nicht die Fehlermeldung erscheinen, dass der Wert des Feldes nicht mehr geändert werden darf, wenn der Status=xyz ist.)

vandyke hat geschrieben:Bei ersterem musst du auch OnAfterGetDatabaseTableTriggerSetup abonnieren und OnDatabaseModify auf TRUE setzen.
Selbstverständlich ist OnAfterGetDatabaseTableTriggerSetup abonniert. Dort wird kurz nachgesehen, ob die übergebene TableId als "Source Table No." in der Synchronisationseinrichtung existiert und OnDatabaseModify entsprechend auf TRUE gesetzt, damit das Event OnAfterOnDatabaseModify ausgelöst wird.
(Theoretisch und praktisch wird das Event auch durch zahlreiche andere Funktionen [wie Workflow, ...] schon gesetzt, aber man sollte sich ja niemals auf andere verlassen, daher wird es nochmal für diesen speziellen Fall geprüft und gesetzt.)

fiddi hat geschrieben:ob xRec gefüllt ist oder nicht hatte ich gerade irgendwo.
Im OnAfterOnDatabaseModify gibt es keinen xRec.
In meinem Fall ist mir der xRec auch egal, denn es wird ja immer SourceRecRef gegen TargetRecRef geprüft.
Auch CurrFieldNo ist für uns in diesem Fall uninteressant, denn wir wollen ja ausdrücklich, dass auch bei Änderungen durch Programmcode die Synchronisation angestoßen wird, daher haben wir ja auch den OnAfterOnDatabaseModify abonniert und nicht den OnAfterOnGlobalModify.

Re: Kein Rollback bei Error nach EventSubscriber

28. April 2020 14:32

Hallo Timo,

In fast allen Situationen funktioniert das auch zuverlässig und der Error löst einen Rollback aus, der sich bis zu dem Modify der Herkunftstabelle auswirkt und auch nicht mit einem anschließenden F5 ausgetrickst werden kann.
Nur bei diesem einen Feld in dieser einen Tabelle kann ich den (unzulässigen) Wert nach dem Error trotzdem durch F5 in dem Datensatz abspeichern.


Hast du den Vorgang mal mit Code Coverage untersucht und geprüft, welche Codezeilen durchlaufen werden?
Ich gehe davon aus, dass hier auch kein impliziter Commit (z.B. IF-RUN) in Frage kommt, oder?
Hat das Feld bei dem das Problem besteht einen besonderen Datentyp?

Re: Kein Rollback bei Error nach EventSubscriber

28. April 2020 16:52

Ok,

mich haben deine Erklärungen etwas durcheinander gebracht, da zum Teil widersprüchlich.

Um das mal zusammenzufassen:

1. Du hast einen Auftrag. Bei Freigabe wird auf Grundlage dieses Auftrages ein Arbeitsauftrag erstellt.
2. Auftrag wird zurückgesetzt und es wird das Feld "Menge" um 1 erhöht.
-------->
3. Diese Änderung wird im OnAfterOnDatabaseModify Event abgefangen und anhand einer Einrichtungstabelle geprüft.
4. Da das Feld "Menge" für die Verkaufszeile in der Einrichtungstabelle mit einer Zieltabellenangabe vorhanden ist, wird der Datensatz der Zieltabelle geholt und per SourceFieldRef.VALUE <> TargetFieldRef.VALUE verglichen.
------->
5. Gibt es einen Unterschied, so wird ein IF ToValidate THEN TargetFieldRef.VALIDATE(SourceFieldRef.VALUE) ELSE TargetFieldRef.VALUE := SourceFieldRef.VALUE; gemacht.
6. Beim VALIDIEREN der "Menge" kommt dann ein ERROR, weil der Status des Arbeitsauftrags Stufe x überschreitet hat. (Prüfung eben im ValidateTrigger vom Feld "Menge" in der Zieltabelle)

Also meine Vermutung wäre eigentlich auch, wie du schon selbst als erstes vermutet hast, eine andere Programmierung. Du hast ja schon an einigen Stellen nachgesehen. Mich hat es nur verwirrt, dass es einmal heißt, es steht nix im ValidateTrigger und dann befindet sich ja doch die eigentliche Prüfung im ValidateTrigger. Ich fasse daher einfach mal meine Ansatzpunkte zusammen. Die da wären:

Zwischen 2. und 3. können Events existieren, die sich auf den ValidateTrigger vom Feld "Menge" beziehen. Auch den ValidateTrigger von der Page nicht vergessen. Dann kommt auch noch OnBeforeModifySalesLine.
Auch eine andere Programmierung kann den OnAfterOnDatabaseModify Event Trigger abonniert haben. Ja es könnte sogar auch an einer Programmierung von einem anderen Feld liegen, denn der OnAfterOnDatabaseModify Trigger wird ja erst bei verlassen des ganzen Datensatzes ausgeführt. Vielleicht auch ein SendKeys F5 irgendwo "versteckt"?
Zwischen 4. und 5. passiert ja sicher noch mehr. Es werden ja sicher mehrere Felder per Schleife geprüft. Das da vorher schon was "passiert" ist?

Ist denn der Fehler immer reproduzierbar bei genau einem zu synchronisierenden Feld?
Kommt dann der "Änderung verwerfen?" Dialog und bei OK wird Rollback gemacht, bei Abbrechen und dann F5 wird kein (kompletter) Rollback gemacht?

Und um einige Fragen aufzuklären:

- "Validateänderungen über RecordRefs"
Damit meine ist so eine Prüfung im ModifyTrigger einer Tabelle: Rec.Field <> xRec.Field. NAV erkennt keinen Unterschied; auch wenn das Field vorher mit FieldRef.VALIDATE(irgendwas) aktualisiert worden ist. Ok, tut jetzt nix zur Sache. Aber Beispiel wäre: Update des Verkäufercodefeldes in der Debitorentabelle über die Konfigurationspakete. Der Standard prüft im ModifyTrigger eben mit Rec <> xRec, ob er eine Änderung zum verbundenen Kontakt synchronisieren muss. Da die Konfigurationspakete auch mit Referenzen arbeiten, wird die Änderung nicht erkannt! Es erfolgt kein Update am Kontakt!

- xRecRef: Doch da kommst du ran. Hab ich ja auch schon geschrieben. Der RecRef enthält ja schon die (ungeschriebene) Änderung. Also holst du dir einfach mit xRecRef.GET(RecRef.RECORDID) den (noch) aktuellen Datensatz. daher braucht das Event dir den nicht mitliefern. Vielleicht kannst du ja auf diese Weise Prüfen, ob an deiner Stelle der xRecRef unzulässigerweise schon die Änderung aufweist. Sprich: Eine andere Programmierung hat schon ein COMMIT gemacht.



Witzigerweise bin ich heute auch auf ein Problem mit dem gleichen Event gestoßen. Ich prüfe damit, ob jemand überhaupt ein Feld ändern darf. Wenn nicht, werfe ich auch ein ERROR. Dahinter steckt auch eine Einrichtungstabelle. Zudem kann ich erlaubte Werte in der Einrichtungstabelle hinterlegen. So dass ein Nutzer nur bestimmte Sachen eingeben kann. So passiert es z.B. dass der ERROR kommt mit der Info für erlaubte Feldwerte. Im "Änderung verwerfen" Dialog kann ich so auf abbrechen gehen und dann einen der erlaubten Feldwerte eintragen. Nun gibt es aber seit heute mit einer anderen Tabelle ein Problem, wo das nicht funktioniert. Das heißt, ich verliere in jedem Fall meine Feldeingaben, denn auch ein erlaubter Wert wird nicht angenommen um den ERROR aufzulösen. Ich muss die Änderungen verwerfen und kann erst im Anschluss einen erlaubten Wert eingeben. Wenn ich vorher in besagter Tabelle versuche den ERROR mit einer Eingabe eines erlaubten Wertes aufzulösen, dann kommt ein zusätzlicher Fehler: "Dieses Feld kann nicht überprüft werden, da die Schlüsselfelder ungültig sind" Google sagt: Ein Bug in 2009. Wir nutzen aber 2016. Möööglicherweise, weil der Primärschlüssel vielleicht eine GUID ist!? (Ich habe noch nicht genug getestet)


Was wir dringend bräuchten, wäre ein OnAfterOnFieldValidate(FieldRef) / OnBeforeOnFieldValidate(FieldRef) Event. Das wäre schön.

VG

Re: Kein Rollback bei Error nach EventSubscriber

29. April 2020 08:31

jm hat geschrieben:Hast du den Vorgang mal mit Code Coverage untersucht und geprüft, welche Codezeilen durchlaufen werden?
Ich habe sämtlichen Programmcode sowohl mittels Code Coverage, als auch mit dem Object Manager Advanced - "Search String in C/AL Code" auf explizite und implizite Commits untersucht.
An allen auch nur entfernt in Frage kommenden Commits hatte ich schon Breakpoints gesetzt, aber keiner davon wurde angesprungen.
jm hat geschrieben:Hat das Feld bei dem das Problem besteht einen besonderen Datentyp?
Es handelt sich um ein ganz schnödes Code[20]-Feld mit einer simplen Tabellen-Relation auf eine einfache "Code/Beschreibung"-Tabelle.

vandyke hat geschrieben:Um das mal zusammenzufassen:
Deine Zusammenfassung stimmt exakt, nur handelt es sich nicht um das Feld "Menge" (mit viel Nachverarbeitungscode), sondern um ein "dummes" Code-Feld, welches an sich keinen Nachverarbeitungscode enthält.
vandyke hat geschrieben: Mich hat es nur verwirrt, dass es einmal heißt, es steht nix im ValidateTrigger und dann befindet sich ja doch die eigentliche Prüfung im ValidateTrigger.
Sorry für die Verwirrung.
Das Feld in der Herkunftstabelle hat keinerlei Programmcode im OnValidate.
Nur in der Zieltabelle hat das gleichnamige Feld eine Prüfung auf den Status im OnValidate.
vandyke hat geschrieben:Ich fasse daher einfach mal meine Ansatzpunkte zusammen. Die da wären:
Auf dem besagten Feld der Herkunftstabelle gibt es keinerlei direkten EventSubscriber - weder auf Tabellen-, noch auf Page-Ebene.
Den OnAfterOnDatabaseModify haben natürlich zahlreiche Subscriber abonniert. Die habe ich alle schon auf explizite/implizite Commits untersucht und auch debuggt.
Mit xRec(Ref) arbeiten wir in EventSubscribern nicht.

Wenn der Anwender in dem Feld der Herkunftstabelle einen (unzulässigen) Wert einträgt und direkt mit F5 die Page aktualisieren will, dann erscheint der Error und er wird gefragt, ob er die Änderungen rückgängig machen möchte.
Bei Ja wird der eingegebene Wert verworfen, bei Nein bleibt der eingegebene Wert in dem Feld stehen, wurde aber noch nicht gespeichert.
Verlässt der Anwender jetzt den Datensatz, dann bleibt der eingegebene Wert trotzdem in dem Feld stehen und wird auch gespeichert.

Andere Reihenfolge:
Wenn der Anwender in dem Feld der Herkunftstabelle einen (unzulässigen) Wert einträgt und den Datensatz verlassen will, dann erscheint der Error und er bleibt auf dem (noch nicht gespeicherten) Datensatz stehen.
Drückt er jetzt F5, dann erscheint keine weitere Fehlermeldung und der eingegebene Wert wird gespeichert.

vandyke hat geschrieben:Was wir dringend bräuchten, wäre ein OnAfterOnFieldValidate(FieldRef) / OnBeforeOnFieldValidate(FieldRef) Event. Das wäre schön.
Dem kann ich mich nur anschließen. Das wäre echt ein Traum.

Re: Kein Rollback bei Error nach EventSubscriber

29. April 2020 09:33

vandyke hat geschrieben:Was wir dringend bräuchten, wäre ein OnAfterOnFieldValidate(FieldRef) / OnBeforeOnFieldValidate(FieldRef) Event. Das wäre schön.

Das hilft nur begrenzt, und ist nur eine Krücke, welches das Problem nur verschiebt.
In einem ERP ist es nun mal notwendig, das Dinge nur in einer bestimmten Reihenfolge getan werden dürfen.
Dann funktioniert es für die erste Extension wahrscheinlich noch, aber die zweite Extension im gleichen Event richtet wahrscheinlich schon Unsinn an. Du kannst nicht die Logistikbelege mit Extension 1 erstellen/aktualisieren, wenn Extension 2 noch Werte in der VK-Zeile aktualisieren muss, die dort benötigt werden.

Gruß Fiddi

Re: Kein Rollback bei Error nach EventSubscriber

29. April 2020 10:46

Timo Lässer hat geschrieben:Mit xRec(Ref) arbeiten wir in EventSubscribern nicht.
Drückt er jetzt F5, dann erscheint keine weitere Fehlermeldung und der eingegebene Wert wird gespeichert.

Schau doch mal an die Stelle, bevor du TargetFieldRef.VALIDATE(SourceFieldRef.VALUE) machst in den xSourceRecRef.Get(SourceRecRef.RecordID), ob der Wert schon gespeichert wurde.


fiddi hat geschrieben:Das hilft nur begrenzt, und ist nur eine Krücke, welches das Problem nur verschiebt.

Nun ja, das könnte man aber eigentlich bei sämtlichen Events/Triggern sagen. Kommt halt immer darauf an, was man machen möchte. Für Timo und mich wäre das wirklich perfekt. So könnte ich das mit der Feldberechtigung sehr viel schöner umsetzten. Der Benutzer kann sofort nach Feldverlassen eine Rückmeldung erhalten. So wie es momentan ist, erhält der Benutzer erst bei Verlassen des Datensatzes einen eventuellen Fehler und verliert ALLE Eingaben, wenn er die Änderungen verwirft. Und das obwohl der Fehler nur wegen einem Feld auftritt. Man muss natürlich immer wissen, was ich mit dem Event anstellen kann, was vor meiner Programmierung abläuft und ggf. danach. Das betrifft aber jeden Trigger. Genauso gut könnte ich ja meine Programmierung einfach in den FeldTrigger setzen. Ich möchte es aber global haben und nicht JEDES Feld JEDER Tabelle anfassen. Wir wollen ja lediglich prüfen ob eine Feldeingabe zulässig ist. Dafür wäre so ein Event wirklich perfekt.

Grüße

Re: Kein Rollback bei Error nach EventSubscriber

29. April 2020 11:59

Nun ja, das könnte man aber eigentlich bei sämtlichen Events/Triggern sagen.


Da hast du vollkommen recht. :wink:

Gruß Fiddi

Re: Kein Rollback bei Error nach EventSubscriber

29. April 2020 15:34

Ich bin mittlerweile etwas schlauer geworden:

Nach dem Eintragen des Wertes in der Herkunftstabelle wird beim Verlassen des Datensatzes (über das Event OnAfterOnDatabaseModify) die Synchronisation gestartet.
Beim Start der Synchronisation wird ein anwendungsglobales Flag gesetzt, welches der Session mitteilt, dass die Synchronisation aktiv ist.
Durch den (gewollten) Fehler im OnValidate des Zielfeldes läuft die Funktion der Synchronisation (aufgrund des Rollback) nicht bis zum Ende durch und kann somit das Flag nicht zurücksetzen.
Der Anwender erhält (wie erwartet) die Fehlermeldung und kann den Datensatz nicht verlassen.

Versucht der Anwender nun (nach der erschienenen Fehlermeldung) erneut, den Datensatz zu verlassen, will NAV den (noch nicht gespeicherten) Datensatz speichern, was wiederum (über das Event OnAfterOnDatabaseModify) die Synchronisation startet.
Die Synchronisation fragt das anwendungsglobale Flag ab und bekommt zurückgemeldet, dass die Synchronisation zur Zeit noch aktiv ist, wodurch der Aufruf direkt beendet wird.
Somit wird nicht erneut versucht, den Wert in das Zielfeld zu validieren, was wiederum keinen Error auslöst.

Dieses Flag ist jedoch unabdingbar, da ansonsten während der Synchronisation bei jedem Modify in einer Zieltabelle eine weitere Synchronisation angestoßen würde, was in einer Endlosschleife enden würde.

Screenshot1.png

Screenshot2.png


Jetzt muss ich nur noch einen Weg finden, wie ich das Flag im Falle eines Rollbacks wieder zurückgesetzt bekomme und trotzdem sicherstelle, dass die Synchronisation nicht durch ihre Modify in den Zieltabellen weitere Synchronisationen anstößt.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Kein Rollback bei Error nach EventSubscriber

29. April 2020 16:48

Timo Lässer hat geschrieben:...Jetzt muss ich nur noch einen Weg finden, wie ich das Flag im Falle eines Rollbacks wieder zurückgesetzt bekomme und trotzdem sicherstelle, dass die Synchronisation nicht durch ihre Modify in den Zieltabellen weitere Synchronisationen anstößt.

Eigentlich doch nur, indem du die Function SynchronizeFields in eine eigene CU ausgliederst und damit die Transaktion splittest.
Oder eventuell mit meinen angesprochenen Try-Functions.


Was ich mich frage, warum funktioniert es bei dem einen Feld und bei dem anderen nicht?

Re: Kein Rollback bei Error nach EventSubscriber

29. April 2020 22:50

Timo Lässer hat geschrieben:Dieses Flag ist jedoch unabdingbar, da ansonsten während der Synchronisation bei jedem Modify in einer Zieltabelle eine weitere Synchronisation angestoßen würde, was in einer Endlosschleife enden würde.
Jetzt muss ich nur noch einen Weg finden, wie ich das Flag im Falle eines Rollbacks wieder zurückgesetzt bekomme und trotzdem sicherstelle, dass die Synchronisation nicht durch ihre Modify in den Zieltabellen weitere Synchronisationen anstößt.


Also wird doch in beide Richtungen synchronisiert? Oder von der Zieltabelle in eine weitere Zieltabelle, ..., die dann irgendwann wieder zur Herkunftstabelle synchronisieren will? :mrgreen:
Das mag ja alles stimmig sein; klingt aber komisch.

Nun gut .. Speichere doch das Flag in der Singleinstanz CU in einem TempRec. Sollte doch beim Rollback rückgängig gemacht werden. Oder halt, wie hier schon erwähnt, mit der TryFunction.

Grüße