“Wutschen und Wedeln” Teil 3: Evanesco - und weg! Filtern wie die Zauberer
Im dritten Teil meiner kleinen Serie, möchte ich Sie mit einem Zaubertrick vertraut machen, der zumindest mich vor kurzem erst wahnsinnig verblüfft hat.
Vorbereitung
Implementiert war der vermeintliche "Trick" in einer Branchenlösung, in der man, ähnlich einem Buch.-Blatt, Zeilen verbuchen konnte. Diese Zeilen wurden als verbucht gekennzeichnet, danach aber nicht gelöscht. Implementiert war auch eine programmatische Vergabe von Zeilennummern, AutoSplitKey wurde nicht verwendet.
Die Ausgangslage des Buch.-Blattes ist oben zu sehen. Alle Zeilen bis zum 10.01.12 sind bereits gebucht. Die implementierte Buchungsroutine in diesem Beispiel ist recht einfach gehalten und setzt das Buchungsdatum und ein Kennzeichen.
Auch die Funktion zur Vergabe von Zeilennummern ist kein Hexenwerk und erhöht die Nummer immer um 10, Einfügen von Zeilen ist nicht erlaubt. Nicht schön, aber schnell:
Zum Buchen ausgewählt werden immer die letzten Datensätze mit aktuellem Belegdatum, im obigen Fall also nur die Seitenwand vom 23.01.12, Artikel 1960-S nicht, da dazwischen der Artikel vom 20.01.12 liegt.
Natürlich war die tatsächlich implementierte Lösung um einiges komplexer als diese Demonstration, aber es geht hier ja eher um den Effekt.
Der Trick
Also, frisch gebucht mit F9, erhalte ich nach der Routine folgendes Ergebnis:
Es wurde also, natürlich wie erwartet, nur die letzte Zeile 140 gebucht. Füge ich nun eine neue Zeile ein, wird mir die Funktion GetLineNo() die 150 zurückgeben und diese im OnInsert() Trigger der Tabelle setzen. Alles funktioniert also wie erwartet, straight forward wie der gemeine Entwickler zu sagen pflegt.
Ich sage ja immer, entwickeln ist kein Hexenwerk! Programmlogik ist oft einfach zu durchschauen, gerade bei so übersichtlichen Projekten wie diesem. Mit Magie hat das nichts zu tun…
Ups! Oder etwa doch?
Zunächst könnte man daran glauben. Aber wer glaubt schon an Magie? Die eilig im Classic Client aufgerufene Tabelle enthüllt – nichts. Die letzte Zeile ist die Nummer 140. Natürlich existiert sie.
Aber warum ermittelt die Funktion GetNewLineNo(), die nach allen Gesetzen der Logik korrekt arbeiten sollte, offensichtlich die Nummer 130 als letzten Datensatz? Befragen wir den RTC und öffnen eine zweite Instanz der Page:
In der Tat, spannend! Wo ist die 140? Auch nach gefühlt 17 mal F5 ändert sich trotzdem nichts am Ergebnis, in beiden Pages nicht:
Die zwei Pages beide geschlossen und nochmals aufgerufen zeigen 130 als letzten Datensatz. Zauberei vom Feinsten, Ladies and Gentlemen!
Der Hut
Um es vorweg zu nehmen: Ein Neustart des RoleTailored Client beendet die Magie und der Datensatz 140 ist wieder zu sehen. Also ein programmatisches Problem...
Ein Blick in den unteren Teil der Funktion Select(), die vor dem Buchen aufgerufen wird offenbahrt folgendes:
In kurzen Worten zur Funktion Select() am obigen Beispiel:
- Filterung auf das aktuelle Arbeitsdatum (23.01.12).
- Letzten Datensatz ermitteln und Zeilennummer (140) speichern.
- Filter lösen und rückwärts lesen, bis entweder ein bereits gebuchter oder ein Datensatz mit einem Belegdatum ungleich dem Arbeitsdatum gefunden wird (Durchlauf 1: 140, Durchlauf 2: 130). Belegdatum 20.01.12, deshalb Schleife verlassen. Aber Achtung: MyJnl.NEXT(-1) liest noch einen weiteren Datensatz rückwärts, so dass der Zeiger nun auf Zeile 120 steht.
- Wurde einer gefunden, dann den Datensatzzeiger wieder einen vorwärts bewegen, hier auf Zeile 130.
- In der Filtergruppe 1 auf ungebuchte Datensätze und die folgenden Zeilen Filtern: 131..140, das schließt nur die neue Zeile 140 ein, die dann gebucht wird.
Der nächste Schritt die Funktion Deselect():
- In Filtergruppe 1 den Filter auf „Gebucht“ entfernen
- Letzten Datensatz mit aktuellem Arbeitsdatum lesen (140)
- Bei Fund die Zeilen auf folgenden Bereich filtern: 0..139
Der Filter bis 139 würde erklären, warum die Zeile 140 in der aktuellen Page nicht gefunden bzw. nicht angezeigt wird. Aber warum nicht in einer neu geöffneten Page?
Die Auflösung
Es handelt sich dabei um ein Feature!
In Dynamics NAV gibt es die verschiedene Filtergruppen (siehe auch FILTERGROUP Function (Record): https://msdn.microsoft.com/en-us/library/dd338919.aspx). Über die Filtergruppen definieren Sie im allgemeinen Filter, die vom Benutzer nicht mehr gelöst werden dürfen oder sollen. Beispielsweise die Gruppe 2, wenn Sie Filter setzen möchten, die normalerweise über SETTABLEVIEW oder der Eigenschaft SourceTableView gesteuert werden. Diese haben dann Gültigkeit und vererben sich in weitere Objekte, sofern der Datensatz übergeben wird.
Die Gruppe 1 hat dabei eine ganz besondere Bedeutung. In der Online-Hilfe im MSDN finden Sie dazu: „Used for filters that apply globally to the entire application“. Das führt dazu, dass eine neu geöffnete Page auch nur die gefilterten Datensätze anzeigt, also die Datensätze entsprechend der in der Filtergruppe 1 vorhandenen Filter.
Die alten Hasen unter Ihnen werden das aus uralten Navision-Versionen kennen und es wurde zwischenzeitlich entfernt. Dann allerdings in Version Dynamics NAV 5.0 SP1 mit dem Hotfix 28913 auf vielfachen Wunsch wieder eingeführt. Gleiches gilt für Dynamics NAV 2009 SP1/R2.
Der globale Filter in der Gruppe 1 wirkt sich ebenfalls auf temporäre Datensätze aus.
Erläutert wird das Feature im folgenden KB-Artikel: You require a new platform feature to provide the functionality to limit the general visibility for users in Microsoft Dynamics NAV 5.0 with Service Pack 1.
Nun dürfen Sie entscheiden, welche Möglichkeiten Sie über den globalen Filter haben. Schreiben in einer gefilterte Tabelle funktioniert immer, sofern nicht bei aktiviertem Filter lesend der nächste Schlüssel über die Zieltabelle ermittelt werden muss.
Für mich war dieses Feature bis vor Kurzem unbekannt. Sollte es Ihnen auch so gehen, willkommen im Club. Winken Sie nun ab, „das kennen Sie schon“, freuen Sie sich an den 10 Minuten, in denen Sie von Ihrer Arbeit etwas abgelenkt wurden
In diesem Sinne, ran an den Speck!
Carsten Scholling
Microsoft Dynamics Germany
Microsoft Customer Service und Support (CSS) EMEA
Email: cschol@microsoft.com
Microsoft Connect: https://connect.microsoft.com
Online Support: https://www.microsoft.com/support
Sicherheitsupdates: https://www.microsoft.de/sicherheit
Microsoft Deutschland GmbH
Konrad-Zuse-Straße 1
D-85716 Unterschleißheim
https://www.microsoft.de
Comments
Anonymous
February 05, 2012
"Frau K." bedankt sich für das ausführliche Beispiel ;-)Anonymous
February 05, 2012
:PAnonymous
February 06, 2012
Wer kennt das nicht? Man verwendet eine temporäre Record-Variable und wunder sich, warum der Datensatz, den man eingefügt hat, nicht mehr gefunden wird? Und irgendwann in einem Gespräch mit den Kollegen stellt sich herraus, dass einer von Ihnen an einer anderen Stelle die Filtergruppe 1 verwendet hat.