Eine magische Show erwartet Sie mit den berechneten Attributen von ORDA!

Oftmals ist es hilfreich oder sogar unerlässlich, dass Datenbanken flexibel an die Nutzer und ihre Unternehmen in der Computerwelt angepasst werden können. Auch die Kontrolle der zugänglichen Daten ist ein immer wiederkehrendes und heikles Thema. Unter diesem Gesichtspunkt verwenden die Entwickler mitunter komplexe Methoden und Formeln, um den Zugang zu Informationen je nach Kontext oder Zugriffsrechten der Benutzer zu ermöglichen oder einzuschränken.

Lassen Sie uns ein einfaches Beispiel nehmen. In Ihrer Anwendung müssen Sie manchmal eine Liste von Personen anzeigen. In einer der Spalten werden die vollständigen Namen angezeigt, aber in Ihrer Datenbank haben Sie ein Feld für den Vornamen und ein Feld für den Nachnamen. Derzeit schreiben Sie eine Formel in die Spalte der Listbox und müssen die Sortierung der Spalte selbst vornehmen. Wäre es nicht toll, ein berechnetes Feld zu haben, bei dem Sie die Berechnungsformel und die Sortiermethode definieren können und die gesamte Geschäftslogik innerhalb der Klasse und nicht in jeder Schnittstelle haben?

Nun, ab 4D v19 R3 bietet 4D eine Lösung für dieses Problem mit berechneten Attributen.

HDI ORDA Berechnete Attribute

DEMO ORDA Berechnete Attribute

IMAGINE…

Sie haben eine Liste mit Personen, deren Nachnamen, Vornamen, Geburtsdaten, etc.

Stellen Sie sich vor, Sie möchten in einem Formular eine Liste von Personen mit ihrem vollständigen Namen (basierend auf Vorname + Nachname), ihrem Alter (basierend auf dem Geburtsdatum), ihrem aktuellen Foto (basierend auf dem Alter) anzeigen…
Sobald eine Person ausgewählt ist, können Sie Informationen über ihre Eltern, Großeltern, Kinder, Brüder und Schwestern, Onkel und Tanten und nicht zu vergessen die Cousins und Cousinen anzeigen!

Ist das möglich? Ja, natürlich.
Ohne komplizierte Codezeilen im Formular? Ja!

All diese Magie ist dank der berechneten Attribute möglich, auf denen man auch suchen und sortieren kann, genau wie bei den anderen Attributen! Schauen wir uns das genauer an!

Definition und Berechnungen

Um die Leistungsfähigkeit dieses Konzepts zu erklären, beginnen wir mit einem konkreten Beispiel. Eine Datenklasse „Personen“ enthält klassischerweise Attribute wie „Nachname“, „Vorname“, „Adresse“, „Postleitzahl“, „Ort“, „Land“, „Geburtsdatum“ usw.
Von dieser Klasse benötigen wir vielleicht den vollständigen Namen (Nachname + Vorname), das Alter (basierend auf dem Geburtsdatum) oder die vollständige Adresse (als Objekt).
Und wir können sogar noch weiter gehen. Wenn die Beziehungen es zulassen, können die berechneten Attribute sogar dem Entitätstyp (z. B. Vater oder Mutter) oder der Entitätsauswahl (Kinder, Eltern, Großeltern, Geschwister usw.) entsprechen.

Der Zugriff auf diese Attribute wird über die Klasse „peopleEntity“ ermöglicht, in der zu diesem Zweck neue Funktionen definiert werden müssen.

Sie werden aufgerufen, wenn 4D Zugriff auf diese Attribute benötigt, entweder um sie zu lesen (z. B. einfache Anzeige), bei einer Suche oder einer Sortierung und schließlich bei einer möglichen Speicherung nach einer Änderung.
Das Ergebnis von berechneten Attributen, wie z. B. die vollständige Adresse, kann ein anderes berechnetes Attribut benötigen, wie z. B. den vollständigen Namen. Auch diese Art der Rekursion ist möglich; wir werden noch darauf zurückkommen.

Diese functions (get, set sowie query und orderBy, auf die später noch eingegangen wird) müssen innerhalb der Entitätsklasse selbst definiert werden (z.B. peopleEntity)

Zugriff auf berechnete Attribute

Hole

Die erste Funktion, „get“, ermöglicht es, die Art und Weise der Berechnung des Attributs zu definieren. Zu diesem Zweck muss sie das Ergebnis der Berechnung zurückgeben.
Diese Funktion ist die einzige, die zwingend erforderlich ist, um die berechneten Attribute zu verwenden. Nur ihr Vorhandensein entscheidet über die Existenz des Attributs selbst.

Function get fullName($event : Object) -> $result : Text
If (This.firstname=Null)
$result :=This.lastname
Else
If (This.lastname=Null)
$result :=This.firstname
Else
$result :=This.firstname+" "+This.lastname
End if
End if

Offengelegt, lokal … oder nicht?

Wie wird dieses Attribut zugänglich sein, und unter welchen Bedingungen wird es berechnet?

Das Schlüsselwort „exposed“, das zur Definition der Funktion verwendet werden kann, entspricht dem Kontrollkästchen „Exposed“ im Inspektor des Struktur-Editors.

blank

Das Schlüsselwort „local“, das im Client-Server-Modus verwendet wird, bestimmt, ob die Berechnung systematisch auf dem Server oder lokal durchgeführt werden soll, um den Netzwerkzugriff zu begrenzen.

SET

Die zweite Funktion, „set“, ermöglicht die umgekehrte Operation, um reale Attribute aus einem berechneten Attribut zu verändern.
Nehmen wir das Beispiel von „fullname“, so besteht die einfache Regel darin, nach einem Leerzeichen im Attribut zu suchen, um den Wert in „firstname“ und „lastname“ umzuverteilen. Natürlich ist dies nur ein einfaches Beispiel. Wenn der vollständige Name mehrere Leerzeichen enthält, müssen Sie eine komplexere Geschäftsregel anwenden, wie z. B. die Verwendung eines Schrägstrichs (/), und diesen als Priorität behandeln.
z.B.: „Pablo Miguel/de la Casa del Mar“.
Der Vorteil ist, dass diese Regel, wenn sie einmal definiert ist, systematisch angewandt wird, ohne dass Sie sie je nach Eingabekontext neu definieren müssen.

Function set fullName($value: Text)
var $p : Integer
$p :=Position("/"; $value)
If ($p>0)
$p :=Position(" "; $value)
End if
If ($p>0)
This .firstname:=Substring($value; 1; $p-1)
This .lastname:=Substring($value; $p+1)
Else
This .firstname:=""
This .lastname:=$value

End if

Ein „get“ ohne „set“? Und das Gegenteil…

Eine Get-Funktion ist obligatorisch, um Zugriff auf ein berechnetes Attribut zu haben. Eine Set-Funktion ist obligatorisch, um dieses Attribut veränderbar zu machen, aber was ist, wenn nur die eine oder die andere dieser Funktionen vorhanden ist?

Wenn nur Get vorhanden ist, kann das Attribut als„schreibgeschützt“ betrachtet werden und kann nicht geändert werden.

Wenn nur die Funktion “ Set “ vorhanden ist, kann das Attribut zwar geschrieben, aber nicht wieder gelesen werden. Dies ist das Prinzip eines Postfachs oder eines Passworts.

Wie geht es nun weiter?

Die dritte und vierte Funktion query und orderBy sind sehr ähnlich und werden auf dieselbe Weise behandelt.
Diese Funktionen sind nicht zwingend erforderlich, aber ihre Verwendung erhöht die Leistung drastisch, wie wir noch sehen werden. Wenn diese Funktionen nicht definiert sind, muss 4D die „get“ -Funktion für jede Entität ausführen und dann eine sequentielle Sortierung vornehmen. Dies wird wahrscheinlich dazugehören und ist alles andere als optimiert.

Es ist wichtig zu verstehen und sich daran zu erinnern, dass berechnete Attribute keine Indizes haben. Wenn ihre Berechnung jedoch auf Attributen basiert, dann können (oder sollten) diese Attribute indiziert sein!

Aus diesem Grund wird die Möglichkeit angeboten, zu definieren, wie die Suche tatsächlich durchgeführt werden soll, wenn eine Abfrage oder eine Sortierung nach einem berechneten Attribut gestartet wird.

Nehmen wir das Beispiel von fullname, basierend auf den Attributen firstname und lastname (beide indiziert), wird eine Suche des Typs <<fullname = „Paul Smith“ >> wahrscheinlich bedeuten, dass <<firstname = „Paul“>> und <<lastname = „Smith“>>. Es steht Ihnen frei, die Suche zu erweitern und zu entscheiden, dass eine Suche <<fullname = „Pa Sm“ >> bedeutet, dass das <<firstname mit „Pa“>> und das <<lastname mit „Sm“>> beginnt. Oder dass << = „Martin“ >> bedeutet, dass entweder der Nachname oder der Vorname mit „Martin“ beginnt…

Abfrage

Bei der Ausführung der Funktion „Abfrage“, die für ein beliebiges berechnetes Attribut definiert wurde, enthält der empfangene Parameter zwei Eigenschaften, die zum Verständnis der gewünschten Suche erforderlich sind. Mit diesem Wissen kann die Abfrage so umgeschrieben werden, dass ein (oder mehrere) indizierte Attribut(e) verwendet werden und somit eine sequentielle Suche vermieden wird.

$event.operator enthält den Operator in Stringform („==“, „>=“, „<„, etc.)
$event. Value enthält den zu suchenden oder zu vergleichenden Wert, ebenfalls als String.

Das Ergebnis einer Abfragefunktion kann entweder eine Zeichenkette oder ein Objekt sein.

Wenn die Funktion eine Zeichenkette zurückgibt, muss die Zeichenkette eine gültige Abfrage sein.

$result:="nachname = A@ und vorname = B@"

Wenn die Funktion ein Objekt zurückgibt, muss es zwei Eigenschaften enthalten:

  • .query: eine gültige Abfragezeichenkette, die Platzhalter enthalten kann (:1,:2, etc.)
  • .parameters: eine Sammlung von Werten, die in Platzhaltern verwendet werden

$result:=New object("Abfrage"; $query; "Parameter"; $parameters)

Schauen wir uns nun an, wie man die folgende Datenklassenabfrage innerhalb der Abfragefunktion verwaltet!

$es:=ds.people.query("fullname = :1"; "Paul Smith")

Hier ist der vollständige Code der Abfragefunktion:

Function query fullname ($event: Object) -> $result: Object
$fullname :=$event.value
$operator :=$event.operator
$p :=Position(" "; $fullname)
If ($p>0)
$firstname :=Substring($fullname; 1; $p-1)+"@"
$lastname :=Substring($fullname; $p+1)+"@"
$parameters :=New collection($firstname; $lastname)
Else
$fullname :=$fullname+"@"
$parameters :=New collection($fullname)
End if

Case of

: ($operator="==") | ($operator="===")
If ($p>0)
$query :="vorname = :1 und nachname = :2"
Else
$query :="vorname = :1 oder nachname = :1"
End if
: ($operator="!=")
If ($p>0)
$query :="vorname != :1 und nachname != :2"
Else
$query :="vorname != :1 und nachname != :1"
End if
End case
$result :=New object("query"; $query; "parameters"; $parameters)

Sortieren nach

Was die Sortierung betrifft, so ist sie ziemlich ähnlich. In diesem Fall ist das Sortieren von Personen nach ihrem Alter genau dasselbe wie das Sortieren nach ihrem zurückgegebenen Geburtsdatum. Wenn also eine Sortierung nach Alter verlangt wird, ist es klug, das Geburtsdatum, das als Kriterium indiziert ist, zu verwenden.

  • Sortierung nach Beispielen:

$es:=ds.people.all().orderBy("age desc")
$es :=ds.people.all().orderBy("Alter aufsteigend")

  • OrderBy-Funktion:

Function orderBy age($event: Object) -> $result: String
If
($event.operator = "desc")
$result:="Geburtstag asc"
Else
$result
:="Geburtstag desc"
End if

Verwendung von Composite-Indizes

Zusammengesetzte Indizes können in einigen Fällen sehr positiv verwendet werden. Zur Erinnerung: Eine Sortierung nach „Nachname“ und „Vorname“ verwendet weder den Nachnamen- noch den Vornamenindex. Damit diese Art der Sortierung optimiert werden kann, muss es einen Index “ Vorname+Vorname“ oder „Vorname+Nachname“ geben… oder beides.

Im Falle eines berechneten Attributs wie Vollname wird 4D diesen zusammengesetzten Index verwenden, wenn es weiß, dass es sich eigentlich um eine Sortierung nach Vorname + Nachname handelt! Es ist sogar möglich, eine Sortierung nach Nachname + Vorname zu erzwingen , auch wenn der Vorname vor dem Nachnamen steht!

  • Sortierung nach Beispiel:

Form.people:=ds.people.all().orderBy("fullname asc")

  • OrderBy-Funktion:

Function orderBy fullname($event : Object)->$result : Text
If ($event.descending)
$result :="nachname desc, vorname desc"
Else
$result :="nachname asc, vorname asc"
End if

Andere mögliche Typen von COMPUTED-Attributen

In den obigen Abschnitten haben wir berechnete Attribute vom skalaren Typ (Text, numerisch…) behandelt, aber die berechneten Attribute können auch Objekte, Entitäten oder Entitätsselektionen sein !

Einige mögliche Beispiele:

  • fullAddress: Objekt mit beliebig vielen Attributen (Name, Straße, Postleitzahl, Ort, Land, etc.)

Function get fullAddressThis($event: Object) -> $result: Object
$result :=New object
$result .fullName:=This.fullName // Another computed attribute can be used!
$result .address:=This.address
$result .zipCode:=This.zipCode
$result .city:=This.city
$result.state:=This.state
$result .country:country

  • bigBoss: Entität

Function get bigBoss($event: Object) -> $result: cs.peopleEntity
$result :=this.manager.manager

  • coworkers : entitySelection

Function get coworkers($event: Object) -> $result: cs.peopleEntitySelection
$result :=this.manager.directReports.minus(this)

Schlussfolgerung

Berechnete Attribute sind geboren und gut geboren! Sie bringen sowohl Flexibilität und Leistung als auch eine bessere Kontrolle darüber, was zugänglich ist und was nicht. Der Zugriff auf diese Attribute ist so optimiert, dass weder der Speicher noch der Netzwerkzugriff beeinträchtigt werden. Sie sind die einfache Lösung für geschäftliche Anforderungen und erfüllen die gestiegenen Anforderungen der modernen Programmierung.

Für weitere Details lesen Sie bitte diese Dokumentation.

Roland Lannuzel
- Product Owner & 4D Experte - Nach seinem Studium der Elektronik arbeitete Roland als Entwickler und Berater in der industriellen IT-Branche, wo er Lösungen für Kunden mit einer Vielzahl von Datenbanken und Technologien entwickelte. In den späten 80er Jahren verliebte er sich in 4D und setzte es bei der Entwicklung von Geschäftsanwendungen wie Buchhaltungs-, Abrechnungs- und E-Mail-Systemen ein. 1997 trat er schließlich in das Unternehmen ein und leistete einen wertvollen Beitrag, indem er Spezifikationen, Testtools und Demos entwarf, Schulungen durchführte und auf vielen Konferenzen für die 4D Community sprach. Er gestaltet die Zukunft von 4D aktiv mit, indem er neue Funktionen und Datenbankentwicklungstools definiert.