Arbeiten mit Hierarchien in lsFusion

Bild

In verschiedenen Anwendungen besteht häufig die Notwendigkeit, eine hierarchische Darstellung von Objekten zu implementieren. In der Regel wird dies verwendet, um sie durch Angabe von Gruppen zu klassifizieren. Diese Gruppen bilden einen Baum mit dynamischer Tiefe, der dann für die Navigation, Datenaggregation und Parametereinstellung verwendet wird.

In diesem Artikel werde ich zeigen, wie diese Logik in der offenen und kostenlosen lsFusion- Plattform implementiert werden kann.

Nehmen wir als Beispiel eine einfache Logik, in der Sie die Logik von Waren implementieren müssen, die in bestimmten Gruppen gruppiert sind, die eine Hierarchie dynamischer Tiefe bilden. In diesem Fall kann die Ware an einen Zwischenknoten des Baumes gebunden werden.

Deklarieren Sie zunächst gemäß dem Standardschema die Produktgruppenentität als einfache flache Klasse mit Bearbeitungsformularen und einer Liste:
CLASS Group '' ;
name '' = DATA ISTRING [ 50 ] (Group);

FORM group ''
OBJECTS g = Group PANEL
PROPERTIES (g) name

EDIT Group OBJECT g
;

FORM groups ''
OBJECTS g = Group
PROPERTIES (g) READONLY name
PROPERTIES (g) NEWSESSION NEW , EDIT , DELETE

LIST Group OBJECT g
;

NAVIGATOR {
NEW groups;
}

Lassen Sie uns nun aus Gruppen eine Hierarchie machen. Dazu führen wir eine Eigenschaft ein, die einen Link zur übergeordneten Gruppe enthält:
parent = DATA Group (Group);
nameParent ' ' (Group g) = name(parent(g));

Als Nächstes erstellen wir eine Eigenschaft, die die Beziehung zwischen zwei Gruppen rekursiv bestimmt:
level '' (Group child, Group parent) =
RECURSION 1l IF child IS Group AND parent = child
STEP 2l IF parent = parent($parent) MATERIALIZED ;

Nach welchem ​​Prinzip der RECURSION- Operator funktioniert , werde ich in diesem Artikel nicht beschreiben, aber die level- Eigenschaft gibt 2 auf den Grad der "Pfadlänge zwischen Kind und Eltern im entsprechenden Richtungsbaum" zurück. MATERIALISIERT gibt an, dass die Plattform es in einer separaten Tabelle speichern soll, wobei für jedes Paar verbundener Knoten ein separater Datensatz mit dem Ebenenwert in der entsprechenden Spalte vorhanden ist. Bei jeder Änderung der Baumstruktur wird diese Tabelle automatisch neu gezählt.

Zum Beispiel für einen solchen Baum:

Bild

Die Tabelle sieht folgendermaßen aus:

Bild

Darin ist key0 der Nachkommencode und key1 der übergeordnete Code. Die Anzahl der Einträge in dieser Tabelle entspricht ungefähr der Anzahl der Gruppen multipliziert mit der durchschnittlichen Tiefe des Baums. Ein solches Speicherschema ist insofern nützlich, als Sie, wenn Sie alle Nachkommen der Gruppe zählen müssen, nicht auf CTE-Anforderungen zurückgreifen müssen, sondern für diese Tabelle den üblichen JOIN verwenden können.

Ferner kann basierend auf der konstruierten Eigenschaft der kanonische Name der Gruppe berechnet werden:
canonicalName ' ' (Group group) =
GROUP CONCAT name(Group parent), ' / ' ORDER DESC level(group, parent) CHARWIDTH 50 ;

Für die Milchgruppe im obigen Bild wäre der kanonische Name beispielsweise Alle / Lebensmittel / Milchprodukte / Milch . CHARWIDTH wird angegeben, um der Plattform mitzuteilen, welche Breite für diese Eigenschaft (in Zeichen) beim Erstellen der Schnittstelle verwendet werden soll.

Jetzt erweitern wir das Formular zum Anzeigen und Bearbeiten von Gruppen mit neu erstellten Eigenschaften:
EXTEND FORM group
PROPERTIES (g) nameParent, canonicalName
;

EXTEND FORM groups
PROPERTIES (g) READONLY nameParent, canonicalName
;

Ein Formular mit einer Liste von Gruppen in einer flachen Form sieht folgendermaßen aus:

Bild

Fügen Sie nach Abschluss der Logik der Gruppen die Entität Produkt hinzu :
CLASS Product '' ;
name '' = DATA ISTRING [ 50 ] (Product);

Erstellen Sie einen Produktlink zu der Produktgruppe, zu der er gehört:
group '' = DATA Group (Product);
canonicalNameGroup ' ' (Product p) = canonicalName(group(p));

Schließlich erstellen wir ein Formular für die Eingabe von Waren, in dem zwei Elemente enthalten sind: ein Gruppenbaum und eine Warenliste. Für die ausgewählte Baumgruppe werden nur Produkte in der Liste angezeigt, die zu einem Nachkommen des ausgewählten Knotens gehören. Deklarieren Sie zunächst ein Formular und fügen Sie ihm einen Baum mit einer Liste von Gruppen hinzu:
FORM products ''
TREE groups g = Group PARENT parent
PROPERTIES READONLY name(g)
;

Mit dem Befehl TREE wird ein Baum aus Objekten der Group- Klasse erstellt, deren Hierarchie durch die zuvor erstellte übergeordnete Eigenschaft bestimmt wird.

Fügen Sie das Formular dem Navigator hinzu:
NAVIGATOR {
NEW products;
}

In diesem Beispiel erfolgt die Eingabe und Bearbeitung von Waren nicht über separate Dialoge, sondern direkt im Formular. Erstellen Sie dazu eine Aktion, um ein Produkt mit Bezug auf die ausgewählte Gruppe zu erstellen:
newProduct '' (Group g) {
NEW p = Product {
group(p) <- g;
}
}

Fügen Sie nun im zuvor erstellten Formular die Liste der Produkte mit bearbeitbaren Spalten hinzu:
EXTEND FORM products
OBJECTS p = Product
PROPERTIES (p) name, canonicalNameGroup
FILTERS level(group(p), g)
;

Aktivieren Sie die Formularschaltflächen zum Hinzufügen und Entfernen von Waren:
EXTEND FORM products
PROPERTIES newProduct(g) DRAW p TOOLBAR , DELETE (p)
;

Da die Aktion newProduct für eine Produktgruppe definiert ist, muss explizit angegeben werden, dass sie der Symbolleiste mit der Produktliste hinzugefügt werden soll (p).

Das Design muss noch so konfiguriert werden, dass der Baum links und die Liste der Produkte rechts angezeigt wird. Dazwischen befindet sich ein Trennzeichen, mit dem Sie die Größe von Objekten ändern können:
DESIGN products {
OBJECTS {
NEW pane {
type = SPLITH ;
fill = 1 ;
MOVE BOX ( TREE groups);
MOVE BOX (p);
}
}
}

Das endgültige Formular sieht folgendermaßen aus:

Bild

Nachdem die Hierarchie der Produkte und Gruppen erstellt wurde, müssen häufig einige Parameter auf einer der Ebenen festgelegt werden. Darüber hinaus ist der Wert umso höher, je niedriger die Hierarchie angegeben ist. Wenn beispielsweise die Milchgruppe auf 30 und die Milchgruppe auf 20 eingestellt ist, sollte die letzte ausgewählt werden.

Angenommen, Sie möchten die Premium- Option auf diese Weise definieren. Erstellen Sie dazu zunächst die entsprechende Eigenschaft für die Gruppe:
markup ', %' = DATA NUMERIC [ 10 , 2 ] (Group);

Um den gewünschten Wert zu finden, verwenden Sie einfach die Gruppierung mit der Auswahl des letzten Werts:
parentMarkup ' ( ), %' (Group child) =
GROUP LAST markup(Group parent) ORDER DESC level(child, parent) WHERE markup(parent);

In die gewöhnliche Sprache übersetzt, findet dieser Ausdruck ( GROUP ) das letzte ( LETZTE ) Markup in der obersten Gruppe ( Group Parent ) in absteigender Reihenfolge der Entfernung dazu ( ORDER DESC Level (Child, Parent) ), für das dieses Markup vorliegt gegeben ( WHERE Markup (Eltern) ). Hier möchte ich darauf hinweisen, wie lsFusion der natürlichen Sprache entspricht.

Fügen Sie dem Produktformular im Gruppenbaum die oben erstellten Eigenschaften hinzu:
EXTEND FORM products
PROPERTIES (g) markup, parentMarkup READONLY
;

Angenommen, es ist erforderlich, eine Prämie direkt für ein Produkt festzulegen, und diese sollte höher sein als die Prämie für die Gruppe. Erstellen Sie dazu zunächst die primäre Eigenschaft für das Produkt:
dataMarkup ' , %' = DATA NUMERIC [ 10 , 2 ] (Product);

Dann deklarieren wir eine Eigenschaft, die die Prämie des Produkts, falls angegeben, oder die Prämie der Gruppe zurückgibt:
markup ', %' (Product p) = OVERRIDE dataMarkup(p), parentMarkup(group(p));

Fügen Sie danach beide Eigenschaften zum Formular hinzu:
EXTEND FORM products
PROPERTIES (p) dataMarkup, markup READONLY
;

Der Mechanismus zum Festlegen von Prämien für Gruppen und Produkte sieht folgendermaßen aus:

Bild

Fazit


Im obigen Artikel konnten wir die Logik der Waren erstellen, sie zu Gruppen mit einer Hierarchie dynamischer Tiefe zusammenfassen und dem Benutzer die Möglichkeit geben, Prämien auf jeder Ebene festzulegen. All dies dauerte ungefähr 70 bedeutende Codezeilen. Sie können versuchen, wie es online funktioniert, und Ihre Änderungen am Code im entsprechenden Abschnitt der Site (Registerkarte Plattform) vornehmen. Hier ist der gesamte Quellcode, den Sie in das entsprechende Feld einfügen müssen:

Quellcode
CLASS Group '' ;
name '' = DATA ISTRING [ 50 ] (Group);

FORM group ''
OBJECTS g = Group PANEL
PROPERTIES (g) name

EDIT Group OBJECT g
;

FORM groups ''
OBJECTS g = Group
PROPERTIES (g) READONLY name
PROPERTIES (g) NEWSESSION NEW , EDIT , DELETE

LIST Group OBJECT g
;

NAVIGATOR {
NEW groups;
}

parent = DATA Group (Group);
nameParent ' ' (Group g) = name(parent(g));

level '' (Group child, Group parent) =
RECURSION 1l IF child IS Group AND parent = child
STEP 2l IF parent = parent($parent) MATERIALIZED ;

canonicalName ' ' (Group group) =
GROUP CONCAT name(Group parent), ' / ' ORDER DESC level(group, parent) CHARWIDTH 50 ;

EXTEND FORM group
PROPERTIES (g) nameParent, canonicalName
;

EXTEND FORM groups
PROPERTIES (g) READONLY nameParent, canonicalName
;

CLASS Product '' ;
name '' = DATA ISTRING [ 50 ] (Product);

group '' = DATA Group (Product);
canonicalNameGroup ' ' (Product p) = canonicalName(group(p));

FORM products ''
TREE groups g = Group PARENT parent
PROPERTIES READONLY name(g)
;

NAVIGATOR {
NEW products;
}

newProduct '' (Group g) {
NEW p = Product {
group(p) <- g;
}
}
EXTEND FORM products
OBJECTS p = Product
PROPERTIES (p) name, canonicalNameGroup
FILTERS level(group(p), g)
;

EXTEND FORM products
PROPERTIES newProduct(g) DRAW p TOOLBAR , DELETE (p)
;

DESIGN products {
OBJECTS {
NEW pane {
type = SPLITH ;
fill = 1 ;
MOVE BOX ( TREE groups);
MOVE BOX (p);
}
}
}

markup ', %' = DATA NUMERIC [ 10 , 2 ] (Group);

parentMarkup ' ( ), %' (Group child) =
GROUP LAST markup(Group parent) ORDER DESC level(child, parent) WHERE markup(parent);

EXTEND FORM products
PROPERTIES (g) markup, parentMarkup READONLY
;

dataMarkup ' , %' = DATA NUMERIC [ 10 , 2 ] (Product);
markup ', %' (Product p) = OVERRIDE dataMarkup(p), parentMarkup(group(p));

EXTEND FORM products
PROPERTIES (p) dataMarkup, markup READONLY
;

Die oben beschriebene Vorlage kann durch Hinzufügen zusätzlicher Parameter zu den Eigenschaften geändert und auf verschiedene Arten verwendet werden. Beispielsweise werden in einer Implementierung des ERP-Systems die Prämien für Gruppen und Waren auf diese Weise nicht global, sondern für jede Art von Preis separat festgelegt. Darüber hinaus unterscheidet sich die Implementierung in der Komplexität nicht von dem oben beschriebenen Beispiel.

Source: https://habr.com/ru/post/de468047/


All Articles