Records: GET SETFILTER FIND etc.
Verfasst: 26. September 2009 16:33
| Viele NAV-Programmier-Einsteiger scheitern an der Datensatzbeschaffung per C/AL. Wer mit technisch-abstrakten Beschreibungen kein Problem hat, findet mitterweile online schöne Hilfeartikel zum Thema: Essential C/AL Functions - lesen! Dieser Artikel dagegen ist für Programmierneulinge gedacht, die problemorientiert an die Sache gehen möchten. Ich versuche zu beschreiben, wie die "Maschine" denkt und daher Eingaben von euch erwartet: anhand des Beispiels eines Tellerwäschers (ihr) und seinem Helfer (NAV):-) Wer dagegen einen Überblick über die vorhandenen Recordfunktionen und deren Unterschiede zueinander haben möchte, dem empfehle ich den englischsprachigen Eintrag bei mibuso: How to work with record-variables (version 2)? |
Ich gehe im Folgenden davon aus, dass ihr wisst, was Recordvariablen sind und wie ihr diese deklariert.
GET: Auf einen einzigen, ganz bestimmten Datensatz zugreifen
- Ihr seid Tellerwäscher und müsst einen bestimmten Teller vorspülen. Diesen soll euch euer - etwas empfindliche - Kollege reichen. Damit derjenige den einen Teller auf Anhieb findet und Verwechslungen ausgeschlossen sind, beschreibt ihr ihm den Teller eindeutig, z.B. "Den ovalen mit der gelben Farbe!"- und genauso arbeitet GET in Navision.
- Code:
Teller.GET(oval, gelb);- Hierbei ist die Reihenfolge der einzelnen Felder innerhalb der Klammern wichtig - sie muss der Reihenfolge der Primärschlüsselfelder (s.u.) entsprechen.
Euer Helfer weiß nicht, dass gelb eine Farbe und oval eine Form ist. Damit er weiß, welchen Wert er welcher Eigenschaft zuordnen soll, braucht er einer vordefinierte Reihenfolge. - GET erwartet in den Klammern Werte für jedes Schlüsselfeld, jedoch keine namentliche Auflistung der Schlüsselfelder!
Wenn ihr Quelltext der Form- Code:
SalesHeader.GET("Document Type", "No.");
Der nachfolgende Code führt das Gleiche aus:- Code:
MyOptionVar := Rec."Document Type";
MyCodeVar := Rec."No.";
SalesHeader.GET(MyOptionVar, MyCodeVar);
- Was macht RecordXY.GET; ohne Parameter?
Ihr verweist mit der Recordvariable zunächst auf den Gegenstand (Tabelle "Teller") und beschreibt ihn dann eindeutig (Form: oval, Farbe: gelb).
Das, was in NAV einen Datensatz in einer Tabelle eindeutig beschreibt, ist der Primärschlüssel (auch Primary Key oder kurz PK genannt). Ein Primärschlüssel kann aus einem Feld bestehen oder wie hier eben aus mehreren Feldern (Form und Farbe).
Gäbe es eine Tabelle Teller in NAV mit den Primärschlüsselfeldern Form und Farbe, dann hätte euer Befehl in NAV in etwa so gelautet:
Vorsicht Anfängerfalle!
Wo kann ich den Primärschlüssel einer Tabelle nachsehen?
- Wenn es eure Entwicklerlizenz erlaubt, sucht die Tabelle im Object Designer und klickt unten auf "Design". Hier seht ihr eine Auflistung aller Tabellenfelder.
Wählt nun im Menü unter Ansicht -> Keys.
Hier stehen nun ein oder mehrere Datensätze. Nur der oberste ist euer gesuchte Primärschlüssel.
Beispiel:
Stellt euch im Object Designer auf Tabelle 37 (Sales Line) und ruft deren Schlüssel auf.
In der obersten Zeile steht:- Code:
Document Type,Document No.,Line No.
Es handelt sich hier also um einen Primärschüssel aus drei Feldern. - Reicht eure Lizenz nicht aus, dann öffnet in der Anwendung eine Form, die eure Tabelle anzeigt und klickt Ansicht -> Sortierung. Auch hier ist der oberste Eintrag der Primärschlüssel. Stellt NAV auf Englisch um, wenn ihr die englische Bezeichnung der Felder sehen wollt.
- Code:
SalesLine.GET(Auftrag, '1014', 10000); // Achtung, syntaktisch noch nicht richtig- Code:
SalesLine.GET(SalesLine."Document Type"::Order, '1014', 10000);- ihr einen einzigen Datensatz sucht und
- ihn eindeutig durch seine Primärschlüsselfelder beschreiben könnt,
Möchtet ihr ein GET auf die Tabelle Sales Line anwenden (konkret auf die erste Zeile (10000) des Auftrags 1014), erwartet NAV laut Primärschlüssel folgenden Aufbau:
Damit der Compiler den Optionswert "Auftrag" versteht, müssen wir es jetzt nur noch etwas anders schreiben:
Hättet ihr eurem Helfer gesagt: "Bring mir den dreieckigen Teller in Neongrün", hätte der wohl bitterlich geweint, weil er ihn nicht finden kann.
NAV hätte euch dagegen einen Laufzeitfehler ausgegeben.
- Ihr steht an der Spüle und möchtet, dass jemand (NAV) euch nacheinander alle ovalen Teller (Farbe ist also egal) reicht, damit ihr sie spülen könnt. Wie würdet ihr diese "Spülschleife" in NAV abbilden?
- Code:
Teller.SETFILTER(Form, oval); // 1)
IF Teller.FIND('-') THEN // 2)
REPEAT
// spüle Teller
UNTIL Teller.NEXT = 0; // 3)- Hier sagt ihr eurem Helfer, wonach er die Teller auswählen soll.
SETFILTER: zuerst kommt das Feld, auf das ihr filtern möchtet, danach der Wert, auf den ihr filtern möchtet.
Wenn ihr euch das mit (...Form, oval) zu abstrakt vorkommt, denkt euch statt des Kommas einen Doppelpunkt, also (...Form: oval!) - Erst mit FIND(...) läuft euer Helfer los und greift nach dem ersten Teller. In NAV heißt das: Erst jetzt wird eine Abfrage an die Datenbank geschickt (wobei der zuvor gesetzte Filter mit abgegeben wird).
FIND('-') heißt, er soll nach dem ersten Teller greifen, den er findet.
FIND('+') heißt, er soll nach dem letzten Teller greifen, den er findet.
Euer Helfer würde weinen, würde er jetzt nicht mindestens einen Teller finden, auf den diese Beschreibung zutrifft! In NAV hätte dies bedeutet: Laufzeitfehler.
Daher sagt ihr ihm: "Wenn du nichts findest, ist es trotzdem OK."
NAV müsst ihr sagen: IF FIND THEN .... - NEXT (ohne Parameter): Euer Helfer greift nach dem nächsten Teller. Ist keiner mehr da, ergibt das 0 -> Schleife zu Ende.
- ihr mindestens einen Datensatz sucht (meistens jedoch mehrere),
- den/welche ihr nicht durch seine Primärschlüsselfelder beschreiben könnt.
SETFILTER setzt noch keine Abfrage an die Datenbank ab. Diese wird erst mit FIND durchgeführt.
FIND(...) wird verwendet, wenn
Nun gibt es noch SETCURRENTKEY, SETRANGE, FINDSET, FINDFIRST, ISEMPTY usw. - aber für den Anfang soll das reichen.
Ansonsten findet ihr hier einen schönen Blogartikel zu ISEMPTY, FINDFIRST, FINDLAST, FINDSET: Navision Performance-Optimierung auf dem SQL-Server