Findset(True, False) in Verbindung mit IF Codeunit.RUN

Bild Microsoft Dynamics NAV 2016

Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon InfoWissler » 16. September 2021 14:35

Ich habe folgendes programmiert:
Code: Alles auswählen
ImportData.SETRANGE("Processed at", 0DT);
IF ImportData.FINDSET(TRUE, FALSE) THEN BEGIN
 REPEAT
    ProcessSingleImportData(ImportData);
    ImportData.VALIDATE("Processed at", CREATEDATETIME(TODAY, TIME));
    ImportData.MODIFY(TRUE);
    COMMIT;
  UNTIL ImportData.NEXT = 0;
END;


Die Funktion ProcessSingleImportData enthält dabei ein IF Codeunit.Run (mit GETLASTERRORTEXT schreibe ich dabei was in eine Protokoll-Tabelle).

Das ist denke ich im Grunde eine relativ übliche Aufgabe - man hat eine große Menge Daten und man möchte sie verarbeiten und weil man nicht möchte, dass der ganze Job abbricht, nur weil in einem einzigen Datensatz ein Fehler auftritt, arbeitet man mit IF Codeunit.RUN und speichert Fehler ggf. weg.

Allerdings bekomme ich folgende Fehlermeldung bei AusfĂĽhrung der IF Codeunit.RUN - Zeile:
Die unten aufgeführten C/AL-Funktionen sind während Schreibtransaktionen eingeschränkt, da mindestens eine Tabelle gesperrt wird. Form.RunModal ist in Schreibtransaktionen nicht zulässig. Codeunit.Run ist in Schreibtransaktionen nur zulässig, wenn der Rückgabewert nicht verwendet wird. OK := Codeunit.Run() ist z. B. nicht zulässig. Report.RunModal ist in Schreibtransaktionen nur zulässig, wenn RequestForm = FALSE. Report.RunModal(...,FALSE) ist z. B. zulässig. XmlPort.RunModal ist in Schreibtransaktionen nur zulässig, wenn RequestForm = FALSE gilt. XmlPort.RunModal(...,FALSE) ist z. B. zulässig. Verwenden Sie die COMMIT-Funktion, um die Änderungen vor dem Aufruf zu speichern, oder strukturieren Sie den Code anders.


Die Ursache ist der TRUE-Parameter in ImportData.FINDSET(TRUE, FALSE). Dabei passiert ein Locktable und deswegen kann man kein IF Codeunit.Run verwenden.

In der Hilfe zu FINDSET steht zum TRUE-Parameter:
Set this parameter to true if you want to modify any field value within the current key.
This parameter only applies if the ForUpdate parameter is true.
If you set this parameter to false, then you can still modify the records in the set, but these updates will not be performed optimally.
The default value is false.


Ich möchte schon, dass die Updates optimally performed werden. Aber ich möchte auch IF Codeunit.Run nutzen. Was soll ich tun?

Ich vermute mal fast, dass es in diesem Fall, bei dem ich ein Commit nach jedem Datensatz mache, sinnlos ist, den True-Parameter zu setzen und ich einfach mit Findset(False, False) arbeiten sollte (Lösung A)? Ansonsten könnte ich das Commit auch an den Anfang setzen, das würde dann auch mit Findset(TRUE, FALSE) funktionieren, nur ist der TRUE-Parameter in dem Fall dann witzlos, weil ich das Locktable durch das Commit direkt wieder aufhebe (Lösung B)?

Ich tendiere momentan zu Lösung A. Oder sollte man es komplett anders machen? Verbirgt sich hinter dem "will not be performed optimally" noch irgendwas, sodass der True-Parameter außer dem Locktable noch ein weiteres Feature bietet?

Vielen Dank euch!
Zuletzt geändert von InfoWissler am 16. September 2021 15:01, insgesamt 1-mal geändert.
InfoWissler
 
Beiträge: 141
Registriert: 5. November 2010 10:37
Bezug zu Microsoft Dynamics: End-Anwender
Microsoft Dynamics Produkt: Microsoft Dynamics NAV
Microsoft Dynamics Version: 2016

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon enh » 16. September 2021 14:43

Ich wĂĽrd's einfach mal mit den FINDSET Defaults (also false) ausprobieren und dann testen wie die Performance ist.
enh
 
Beiträge: 2330
Registriert: 5. Februar 2014 15:42
Bezug zu Microsoft Dynamics: Microsoft Partner
Microsoft Dynamics Produkt: Microsoft Dynamics NAV

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon InfoWissler » 16. September 2021 15:02

Die Performance des Durchgehens der ImportData-Records an sich ist in Ordnung.

(War sie zunächst nicht, bis wir einen SQL-Index passend zum verwendeten Filter angelegt hatten. Früher hatten wir immer NAV-Keys angelegt und die mit SETCURRENTKEY verwendet, aber da hatte sich zuletzt in vielen Fällen rausgestellt, dass das gerade kontraproduktiv war -was ich bis heute nicht verstanden habe, aber das wäre nochmal ein eigenes Thema wert sonst- und seitdem legen wir SQL-Indizes an, die sich der SQL-Server scheinbar selber automatisch nimmt ohne SETCURRENTKEY-Anweisung. Evtl. doch eine Frage in dem Zusammenhang: der SQL-Index geht auf das Feld "Processed at". Sollte ich dann evtl. Findset(True, True) machen mit Commit am Anfang, weil ich genau das Feld auch ändere, auf das ich filtere? Habe gerade den Filter "ImportData.SETRANGE("Processed at", 0DT)" im Ausgangspost einmal ergänzt, den hatte ich zunächst nicht drin)

Ich fänd halt interessant, was mit "optimally" gemeint ist. Evtl. gar nicht die Performance. Und/oder andere Faktoren, da hatte ich gehofft, dass das evtl. jemand weiß. Evtl. ist ja auch nur das Locktable gemeint, was den Vorteil hat, dass mir da kein anderer Prozess reingrätschen kann, aber das ist so lange sichergestellt bis jemand auf die Idee kommt, den Job manuell parallel zu seinem automatischen Lauf zu starten, was nicht vorkommen sollte. Es gibt keinen anderen Prozess, der sonst auf die zu verarbeitenden Datensätze zugreifen würde. Wenns nur das ist, ists mir halt egal und ich nehme Findset(false, false).

Update: jetzt rolle ich das Thema NAV-Keys hier doch auch nochmal auf: wir hatten bis vor kurzem noch den veralteten Stand zur Verwendung von FIND('-') vs. FINDSET, dass wir FINDSET dann verwendet haben, wenn die Anzahl der Datensätze, die gefunden werden, wahrscheinlich unter 50 (Preset-Number, die es in NAV 2016 nicht mehr gibt) bleibt. Inzwischen wissen wir, dass wir in NAV 2016 generell bei Repeat Until immer Findset verwenden sollten mit passenden Parametern außer es ist wahrscheinlich, dass nicht alle Datensätze durchlaufen werden müssen, weil es z.B. eine Prüfung ist und es eine Abbruchbedingung gibt - nur dann wäre FIND('-') für REPEAT UNTIL zu verwenden. Bisher haben wir bei großen Jobs, bei denen mit REPEAT UNTIL gearbeitet wird, mit FIND('-') gearbeitet. evtl. hätten wir ja in Verbindung mit SETCURRENTKEY dann doch einfach FINDSET verwenden sollen und dann wär alles gut gewesen?
InfoWissler
 
Beiträge: 141
Registriert: 5. November 2010 10:37
Bezug zu Microsoft Dynamics: End-Anwender
Microsoft Dynamics Produkt: Microsoft Dynamics NAV
Microsoft Dynamics Version: 2016

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon Jupiter » 16. September 2021 15:49

Du kannst es schon bei Deinem FINDSET(TRUE) belassen, nur musst Du den COMMIT immer VOR dem IF CODEUNIT.RUN absetzen (und nicht danach). Und die Record-Variable ImportData an die Funktion ProcessSingleImportData am besten per VAR übergeben. Den anschließenden MODIFY auf die ImportData-Variable würde ich per neuen Instanz der Variable machen, denn Du änderst beim MODIFY das gefilterte Feld, u.U. kann Dir passieren, das Du dadurch nicht alle Datensätze erwischst (wenn Du wie jetzt MODIFY ohne die neue Instanz machst).
Jupiter
 
Beiträge: 160
Registriert: 17. Juni 2007 15:17
Bezug zu Microsoft Dynamics: Microsoft Partner
Microsoft Dynamics Produkt: Microsoft Dynamics NAV

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon Timo Lässer » 16. September 2021 16:27

Jupiter hat geschrieben:Du kannst es schon bei Deinem FINDSET(TRUE) belassen, nur musst Du den COMMIT immer VOR dem IF CODEUNIT.RUN absetzen (und nicht danach).

Dann kann er sich das FINDSET(TRUE) aber auch gleich sparen, denn der Parameter besagt, dass die Daten mit der Absicht, sie zu ändern gelesen werden sollen, und es wird eine Transaktion gestartet, welche direkt danach durch den COMMIT wieder beendet wird. (Seine vorgeschlagene Variante A)
Alles, was innerhalb der IF Codeunit.RUN abläuft ist eine in sich gekapselte, abgeschlossene Transaktion.

Einen passenden NAV-SchlĂĽssel zu den gesetzten Filtern anlegen ist fĂĽr die Performance natĂĽrlich optimal.
Da braucht man dann auch nicht noch explizit einen SETCURRENTKEY absetzen, damit der SQL-Server ihn verwendet, denn für das Suchen der Daten in der Tabelle nutzt der SQL-Server immer nur den Index, den er für richtig hält.
Was man mit SETCURRENTKEY ĂĽbergeben hat, wird anschlieĂźend nur in der ORDER BY Klausel fĂĽr die Reihenfolge der Ausgabe berĂĽcksichtigt.
Gruß, Timo Lässer

Frage beantwortet? Schreibe bitte "[Gelöst]" vor den Titel deines ersten Beitrags.
Bitte erst suchen, dann fragen. Bitte beachte den kleinen Community-Knigge.
Kein Support per PN, E-Mail, Instant Messanger, Soziale Netzwerke, Telefon oder Fax! DafĂĽr ist dieses Forum da.
Hier kannst du fĂĽr MSDynamics.de spenden.
Benutzeravatar
Timo Lässer
Administrator
Administrator
 
Beiträge: 5274
Registriert: 14. November 2004 22:18
Wohnort: DE 49716 Meppen
Arbeitsort: DE 49733 Haren (Ems)
Bezug zu Microsoft Dynamics: End-Anwender
Microsoft Dynamics Produkt: Microsoft Dynamics NAV
Microsoft Dynamics Version: 1.10a - 2018, BC14, BC21

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon InfoWissler » 16. September 2021 16:39

Jupiter hat geschrieben:Und die Record-Variable ImportData an die Funktion ProcessSingleImportData am besten per VAR ĂĽbergeben.

Aus Performancegründen? Mein Credo ist beim Thema Var eigentlich, dass ich das nur verwende, wenn ich die Variable auch wirklich in der Funktion, in die ich sie per Var übergebe, ändern möchte. Hatte aber auch schonmal gehört, dass Var performanter ist, nur bisher noch nicht den Druck, dass genau ein Funktionsaufruf so langsam war, dass ich den hätte verbessern müssen.

Jupiter hat geschrieben:Den anschließenden MODIFY auf die ImportData-Variable würde ich per neuen Instanz der Variable machen, denn Du änderst beim MODIFY das gefilterte Feld, u.U. kann Dir passieren, das Du dadurch nicht alle Datensätze erwischst (wenn Du wie jetzt MODIFY ohne die neue Instanz machst).

Das ist soweit ich weiß nicht mehr aktuell. Früher habe ich das auch so gemacht, dass ich mir mit ImportHead2.GET die Variable nochmal zum Modifzieren geholt hätte, aber in NAV 2016 (und ich glaube auch in einigen früheren Versionen) ist das aber kein Thema mehr, dass sich NAV da verhaspeln kann, wenn man auf Felder filtert, deren Werte man dann in der Schleife anpasst.

@Timo, alles klar, danke. Dann würde ich demnächst mal einen NAV-Key statt eines SQL-Index anlegen und mal schauen, ob das den gleichen Effekt hat, wenn ich wieder das Problem habe, dass ein Repeat Until langsam ist aufgrund der Filterung, weil es dazu noch keinen passenden Schlüssel gibt.
InfoWissler
 
Beiträge: 141
Registriert: 5. November 2010 10:37
Bezug zu Microsoft Dynamics: End-Anwender
Microsoft Dynamics Produkt: Microsoft Dynamics NAV
Microsoft Dynamics Version: 2016

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon enh » 16. September 2021 17:12

InfoWissler hat geschrieben:
Jupiter hat geschrieben:Den anschließenden MODIFY auf die ImportData-Variable würde ich per neuen Instanz der Variable machen, denn Du änderst beim MODIFY das gefilterte Feld, u.U. kann Dir passieren, das Du dadurch nicht alle Datensätze erwischst (wenn Du wie jetzt MODIFY ohne die neue Instanz machst).

Das ist soweit ich weiß nicht mehr aktuell. Früher habe ich das auch so gemacht, dass ich mir mit ImportHead2.GET die Variable nochmal zum Modifzieren geholt hätte, aber in NAV 2016 (und ich glaube auch in einigen früheren Versionen) ist das aber kein Thema mehr, dass sich NAV da verhaspeln kann, wenn man auf Felder filtert, deren Werte man dann in der Schleife anpasst.

Ich bin mir ziemlich sicher dass das nachwievor relevant ist. Hatte das Problem definitiv schon in NAV 2017.

InfoWissler hat geschrieben:@Timo, alles klar, danke. Dann würde ich demnächst mal einen NAV-Key statt eines SQL-Index anlegen und mal schauen, ob das den gleichen Effekt hat, wenn ich wieder das Problem habe, dass ein Repeat Until langsam ist aufgrund der Filterung, weil es dazu noch keinen passenden Schlüssel gibt.

Das wĂĽrde ich ohnehin immer in NAV machen und nie in SQL.
enh
 
Beiträge: 2330
Registriert: 5. Februar 2014 15:42
Bezug zu Microsoft Dynamics: Microsoft Partner
Microsoft Dynamics Produkt: Microsoft Dynamics NAV

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon Jupiter » 16. September 2021 17:30

InfoWissler hat geschrieben:Aus PerformancegrĂĽnden?

Zum einen ja, aus Performancegründen, zumindest bei der massenhaften Datenverarbeitung bringt es was, glaube ich. Zum anderen kann Dir später passieren, dass die Funktion ProcessSingleImportData den Datensatz doch ändert (da z.B. neue Programmierung hinzugekommen ist), spätestens dann bekommst Du bei Deinem MODIFY in der Haupt-Schleife eine Fehlermeldung "Der Datensatz wurde inzwischen geändert"
Jupiter
 
Beiträge: 160
Registriert: 17. Juni 2007 15:17
Bezug zu Microsoft Dynamics: Microsoft Partner
Microsoft Dynamics Produkt: Microsoft Dynamics NAV

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon InfoWissler » 20. September 2021 09:41

enh hat geschrieben:
InfoWissler hat geschrieben:
Jupiter hat geschrieben:Den anschließenden MODIFY auf die ImportData-Variable würde ich per neuen Instanz der Variable machen, denn Du änderst beim MODIFY das gefilterte Feld, u.U. kann Dir passieren, das Du dadurch nicht alle Datensätze erwischst (wenn Du wie jetzt MODIFY ohne die neue Instanz machst).

Das ist soweit ich weiß nicht mehr aktuell. Früher habe ich das auch so gemacht, dass ich mir mit ImportHead2.GET die Variable nochmal zum Modifzieren geholt hätte, aber in NAV 2016 (und ich glaube auch in einigen früheren Versionen) ist das aber kein Thema mehr, dass sich NAV da verhaspeln kann, wenn man auf Felder filtert, deren Werte man dann in der Schleife anpasst.

Ich bin mir ziemlich sicher dass das nachwievor relevant ist. Hatte das Problem definitiv schon in NAV 2017.

Ich bin mir ziemlich sicher, dass das nicht mehr relevant ist. Ein Kollege meinte das vor ein paar Jahren, dass das Problem nicht mehr aktuell ist und ich war da auch sehr skeptisch und habe Tests gemacht mit COUNT vorher und nachher und es hat funktioniert. Sicher, dass es in der 2017er-Version nicht ein Bug in einem bestimmten Build war oder dass das Problem evtl. doch eine andere Ursache hatte?
InfoWissler
 
Beiträge: 141
Registriert: 5. November 2010 10:37
Bezug zu Microsoft Dynamics: End-Anwender
Microsoft Dynamics Produkt: Microsoft Dynamics NAV
Microsoft Dynamics Version: 2016

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon enh » 20. September 2021 17:24

Ich bin mir sicher dass ich schon mehrfach vergessen hatte das ordentlich zu programmieren und dabei auf die Nase gefallen bin. Kann sein dass es bei Nicht-Primärschlüssel funktioniert oder sowas in der Art, so genau hab ich das nicht mehr in Erinnerung. Aber es ist mir zu 100% schon mehrfach in NAV 2017 passiert dass ich einfach in der Variable in der ich gefiltert hatte geändert habe und dabei dann nicht über alle Datensätze gelaufen bin weil NAV dann umsortiert hat.
enh
 
Beiträge: 2330
Registriert: 5. Februar 2014 15:42
Bezug zu Microsoft Dynamics: Microsoft Partner
Microsoft Dynamics Produkt: Microsoft Dynamics NAV

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon fiddi » 20. September 2021 17:33

Hallo,

ich kann mir nicht vorstellen das das funktioniert, den Primary- Key der Schelife zu ändern, und dann zu glauben der läuft dann mit dem ursprünglichen Recordset weiter. Das u.U. so aussieht, als ob es funktioniert kann auch an schlecht gewählten Testdaten liegen, oder an einem Modify(false) statt einem Modify(true);

Ich wäre da vorsichtig, spätestens, wenn der Modify andere Records deines gelesenen Recordsets ändert, wird es brenzlig.

GruĂź Fiddi
Wer aufhört besser zu werden, hat aufgehört gut zu sein. (frei nach Philip Rosenthal)
Frage beantwortet? Schreibe bitte [Gelöst] vor den Titel des ersten Beitrags.
Bitte erst suchen, dann fragen. Bitte beachte den kleinen Community-Knigge.
Kein Support per PN, Mail, IM oder Telefon! DafĂĽr ist dieses Forum da.
fiddi
Moderator
Moderator
 
Beiträge: 7091
Registriert: 9. Juni 2008 10:13
Realer Name: Hans Heinrich Fiddelke
Arbeitsort: Bremen
Bezug zu Microsoft Dynamics: Microsoft Partner
Microsoft Dynamics Produkt: Microsoft Dynamics NAV
Microsoft Dynamics Version: NAV2.6-aktuell

Re: Findset(True, False) in Verbindung mit IF Codeunit.RUN

Beitragvon Timo Lässer » 21. September 2021 08:19

Und selbst, wenn FINDSET(TRUE,TRUE) wie in der Dokumentation beschrieben funktionieren sollte, so kann dir niemand versichern, dass es nicht in irgendeinem Cumulative Update versehentlich doch nicht funktioniert.
Solche "unerwartete Programmverhalten" haben vor allem die "alten Hasen" leider schon zu häufig erlebt, daher die Empfehlung:
Wenn man Felder der aktuellen Sortierreihenfolge ändern möchte/muss, sollte man dies immer über eine zweite Record-Variable machen, da nur dann gewährleistet ist, dass der Datensatzzeiger im ursprünglichen Recordset immer noch an der erwarteten Stelle steht.
Gruß, Timo Lässer

Frage beantwortet? Schreibe bitte "[Gelöst]" vor den Titel deines ersten Beitrags.
Bitte erst suchen, dann fragen. Bitte beachte den kleinen Community-Knigge.
Kein Support per PN, E-Mail, Instant Messanger, Soziale Netzwerke, Telefon oder Fax! DafĂĽr ist dieses Forum da.
Hier kannst du fĂĽr MSDynamics.de spenden.
Benutzeravatar
Timo Lässer
Administrator
Administrator
 
Beiträge: 5274
Registriert: 14. November 2004 22:18
Wohnort: DE 49716 Meppen
Arbeitsort: DE 49733 Haren (Ems)
Bezug zu Microsoft Dynamics: End-Anwender
Microsoft Dynamics Produkt: Microsoft Dynamics NAV
Microsoft Dynamics Version: 1.10a - 2018, BC14, BC21


ZurĂĽck zu NAV 2016

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast