Eine Entity-Selection ist ein Objekt, das eine oder mehrere Referenzen auf Entities der gleichen Dataclass enthält. Eine Entity-Selection kann 0, 1 oder X Entities aus der Dataclass enthalten, wobei X die Gesamtzahl der in der Dataclass enthaltenen Entities darstellen kann. Entity-Selections können folgendes sein:
"shareable" oder "alterable" (änderbar)
"sortiert" oder "unsortiert"
Diese Punkte werden weiter unten erläutert.
Entity-Selections werden in der Regel über eine Abfrage (query) erstellt oder aus einem Verknüpfungsattribut zurückgegeben. Zum Beispiel:
brokers:=ds.Person.query("personType = broker")
Dieser Code gibt in brokers alle Personen vom Typ Broker zurück. Um auf eine Entity der Selection zuzugreifen, verwenden Sie eine ähnliche Syntax wie beim Zugriff auf ein Element in einer Collection. Zum Beispiel:
theBroker:=brokers[0] //Entity-Selections gehen von 0 aus
Die Methode entitySelection.orderBy() gibt eine neue Entity-Selection gemäß den definierten Sortierkriterien zurück. Zum Beispiel:
brokers:=brokers.orderBy("name") //gibt eine sortierte Selection zurück
Dieser Code gibt in brokers die gleiche Entity-Selection der Entities person zurück, jedoch sortiert nach Namen.
Alternativ können Sie eine Entity-Selection auch über ein Verknüpfungsattribut zurückgeben. Zum Beispiel:
Dieser Code ordnet den brokerCompanies alle verbundenen Unternehmen der Personen in der Entity-Selection brokers zu, die das Verknüpfungsattribut myCompany annehmen. Die Verwendung von Verknüpfungsattributen sind ein leistungsstarker und einfacher Weg, um in den verknüpften Entities nach oben und unten zu navigieren.
Um wiederholte Aktionen an Entities in einer Entity-Selection durchzuführen, wie Werte bestimmter Attribute abrufen und ändern, können Sie die Struktur For each...End for each verwenden. Zum Beispiel:
C_OBJECT(emp) For each(emp;ds.Employees.all()) If(emp.Country="UK")
emp.salary:=emp.salary*1,03
emp.save() End if End for each
Ein Verknüpfungsattribut vom Typ "related entities" verwenden (siehe unten)
Sie können gleichzeitig beliebig viele verschiedene Entity-Selections für eine Dataclass anlegen und verwenden. Beachten Sie, dass eine Entity-Selection nur Referenzen auf Entities enthält. Verschiedene Entity-Selections können Referenzen auf die gleichen Entities enthalten.
Hinweis: Eine Entity-Selection ist nur in dem Prozess definiert, wo sie erstellt wurde. So können Sie beispielsweise nicht eine Referenz auf eine Entity-Selection in einer Interprozessvariablen speichern und in einem anderen Prozess verwenden.
Alle Speicherattribute (Text, Nummer, Boolean, Datum) sind sowohl als Eigenschaften von Entity-Selections als auch von Entities verfügbar. In Verbindung mit einer Entity-Selection gibt ein skalares Attribut eine Collection von skalaren Werten zurück. Zum Beispiel:
locals:=ds.Person.query("city = :1";"San jose") //Entity-Selection von Personen
localEmails:=locals.emailAddress //Collection von E-Mail Adressen (Strings)
Dieser Code gibt in localEmails eine Collection von E-Mail Adressen als Strings zurück.
Zusätzlich zu den verschiedenen Wegen für Abfragen (query) können Sie Verknüpfungsattribute als Eigenschaften von Entity-Selections verwenden, um neue Entity-Selections zurückzugeben. Nehmen wir z.B. folgende Struktur:
myParts:=ds.Part.query("ID < 100") //gibt Teile (parts) mit ID unter 100 zurück $myInvoices:=myParts.invoiceItems.invoice //Alle Rechnungen mit mindestens einem Rechnungseintrag, verknüpft mit einem Teil in myParts
Die letzte Zeile gibt in $myInvoices eine Entity-Selection aller Rechnungen zurück, die mindestens einen Rechnungseintrag haben, verknüpft mit einem Teil (part) in der Entity-Selection myParts. Wird ein Verknüpfungsattribut als Eigenschaft einer Entity-Selection verwendet, ist das Ergebnis immer eine andere Entity-Selection, selbst wenn nur eine Entity zurückgegeben wird. Werden keine Entities zurückgegeben, ist das Ergebnis eine leere Entity-Selection, nicht Null.
Eine Entity-Selection kann shareable (von mehreren Prozessen lesbar, aber nach Erstellung nicht mehr veränderbar) oder alterable (nur vom aktuellen Prozess nutzbar, dafür aber änderbar) sein.
Eine shareable Entity-Selection hat folgende Merkmale:
Sie lässt sich in einem shared object bzw. shared collection speichern und kann zwischen mehreren Prozessen oder Workern geteilt werden.
Sie lässt sich in mehreren shared objects oder shared collections speichern bzw. in einem shared object oder collection, welche bereits zu einer Gruppe gehören (sie hat keinen locking identifier).
Sie erlaubt nicht Hinzufügen neuer Entities. Versuchen Sie, eine Entity in einer shared Entity-Selection hinzuzufügen, wird ein Fehler ausgelöst (1637 - Diese Entity-Selection lässt sich nicht verändern). Sie müssen diese zuerst mit der Funktion entitySelection.copy( ) in eine non-shareable Entity-Selection umwandeln, bevor Sie entitySelection.add() aufrufen.
Hinweis: Die meisten Funktionen für Entity-Selections (wie entitySelection.slice(), entitySelection.and( )...) unterstützen shareable Entity-Selections, da sie die ursprüngliche Entity-Selection nicht verändern müssen (sie geben eine neue zurück).
Eine alterable Entity-Selection hat folgende Merkmale:
Sie lässt sich weder zwischen mehreren Prozessen teilen, noch in einem shared object oder shared collection speichern. Versuchen Sie, eine non-shareable Entity-Selection in einem shared object oder collection zu speichern, wird ein Fehler ausgelöst (-10721 - Nicht unterstützter Wertetyp in einem shared object oder shared collection)
Sie erlaubt Hinzufügen neuer Entities, sie unterstützt z.B. die Funktion entitySelection.add().
Beim Erstellen der Entity-Selection wird definiert, ob sie shareable oder alterable ist. Das lässt sich danach nicht mehr ändern. Mit der Function entitySelection.isAlterable( ) oder dem Befehl OB Is shared sehen Sie, was definiert wurde.
Eine neue Entity-Selection ist in folgenden Fällen shareable:
Die neue Entity-Selection wird mit entitySelection.copy( ) oder OB Copy explizit als alterable kopiert (z.B. ohne die Option ck shared).
Beispiel:
$toModify:=ds.Company.all().copy() //$toModify is alterable
Eine neue Entity-Selection erbt die Definition für die ursprüngliche Entity-Selection in folgenden Fällen:
Die neue Entity-Selection ergibt sich aus einer der ORDA Class Functions, die auf eine vorhandene Entity-Selection angewendet werden (entitySelection.query(), entitySelection.slice(), etc.).
Die neue Entity-Selection basiert auf einer Verknüpfung:
entity.{attributeName} (z.B. company.employees) wenn attributeName ein Verknüpfungsattribut Eine-zu-Viele ist und die Entity zu einer Entity-Selection gehört (dieselbe Definition wie die Entity-Selection entity.getSelection())
entitySelection.{attributeName} (z.B. employees.employer) wenn attributeName ein Verknüpfungsattribut Eine-zu-Viele ist (dieselbe Definition wie die Entity-Selection)
entitySelection.extract wenn die resultierende Collection Entity-Selections enthält (dieselbe Definition wie die Entity-Selection)
Beispiele:
$highSal:=ds.Employee.query("salary >= :1";1000000) //$highSal ist shareable wegen der Suche in dataClass $comp:=$highSal.employer //$comp ist shareable, weil $highSal shareable ist
$lowSal:=ds.Employee.query("salary <= :1";10000).copy() //$lowSal is alterable because of the copy() $comp2:=$lowSal.employer //$comp2 ist alterable, weil $lowSal alterable ist
Hinweis zur Kompatibilität: Mit der Methode dataStore.makeSelectionsAlterable können Sie für alle neuen Entity-Selections in Ihrem Projekt standardmäßig die Definition alterable forcieren. Diese Einstellung wird für neue Projekte nicht empfohlen.
Sie verwenden zwei Entity-Selections, die Sie an einen Worker Prozess übergeben wollen, so dass er Mails an die zutreffenden Kunden senden kann:
var $paid;$unpaid : cs.InvoicesSelection //Entity-Selections für bezahlte und unbezahlte Rechnungen erhalten $paid:=ds.Invoices.query("status=:1";"Paid") $unpaid:=ds.Invoices.query("status=:1";"Unpaid")
//Referenzen auf Entity-Selection als Parameter an den Worker übergeben CALL WORKER("mailing";"sendMails";$paid;$unpaid)
Die Methode sendMails lautet:
#DECLARE($paid cs.InvoicesSelection;$unpaid cs.InvoicesSelection)
var $invoice : cs.InvoicesEntity
//Schleifen von Entity-Selections For each($invoice;$paid) $email.to:=$invoice.customer.address // E-Mail Adresse des Kunden $email.subject:="Payment OK for invoice # "+String($invoice.number) $status:=$transporter.send($email) End for each
For each($invoice;$unpaid) $email.to:=$invoice.customer.address // E-Mail Adresse des Kunden $email.subject:="Please pay invoice # "+String($invoice.number) $status:=$transporter.send($email) End for each
Lokale Entity-Selections können sortiert oder unsortiert sein. Die Funktionsweise ist für beide Arten ähnlich, es gibt Unterschiede in der Performance und den Features. Sie können selbst bestimmen, welcher Typ sich besser für Ihre spezifischen Anforderungen eignet.
Entity-Selections sind immer sortiert, wenn sie
von 4D Server an einen remote Client zurückgegeben werden
Unsortierte Entity-Selections werden auf Bit Tabellen im Speicher aufgebaut. Eine unsortierte Entity-Selection enthält ein Bit pro Entity in der Dataclass, unabhängig ob die Entity tatsächlich in der Selection ist. Jedes Bit ist gleich 1 oder 0, um anzuzeigen, ob die Entity in der Selection enthalten ist oder nicht. Es ist eine sehr kompakte Darstellung jeder Entity. Demzufolge sind Operationen mit unsortierten Entity-Selections sehr schnell und benötigen wenig Speicherplatz. Die Größe einer unsortierten Entity-Selection in Bytes entspricht immer der Gesamtanzahl von Entities in der Dataclass, dividiert durch 8. Beispiel: Sie erstellen eine unsortierte Entity-Selection für eine Dataclass mit 10.000 Entities, das beansprucht bis zu 1.250 Bytes, was ungefähr 1.2K in RAM ausmacht. Dagegen lassen sich unsortierte Entity-Selections nicht sortieren. Sie können sich nicht auf die Position von Entities innerhalb der Selection verlassen. Es kann auch nicht mehrere Referenzen auf eine Entity in der Selection geben: Jede Entity lässt sich nur einmal hinzufügen.
Sortierte Entity-Selections werden auf Arrays vom Typ Lange Ganzzahl im Speicher aufgebaut (mit Entity Referenzen). Jede Referenz auf eine Entity beansprucht 4 Bytes im Speicher. Bearbeiten und Verwalten dieser Selections erfordert mehr Zeit und mehr Speicherplatz als unsortierte Entity-Selections. Sie können dagegen sortiert oder unsortiert sein und Sie können sich auf die Entity Positionen verlassen. Außerdem können Sie mehrere Referenzen auf dieselbe Entity hinzufügen.
Die Übersicht zeigt die Hauptmerkmale:
Feature
Unsortierte Entity-Selection
Sortierte Entity-Selection
Bearbeitungsgeschwindigkeit
sehr schnell
langsamer
Größe im Speicher
sehr klein
größer
Kann mehrere Referenzen auf eine Entity enthalten
nein
ja
Aus Optimierungsgründen erstellt 4D ORDA standardmäßig unsortierte Entity-Selections, außer Sie verwenden die Methode orderBy( ) oder geeignete Optionen (siehe unten). In dieser Dokumentation bezieht sich Entity-Selection in der Regel auf eine "unsortierte Entity-Selection". Andernfalls wird das explizit angegeben.
Wie oben erwähnt, erstellt und behandelt ORDA standardmäßig unsortierte Entity-Selections als Ergebnis von Operationen wie Anfragen oder Vergleiche wie and( ). Sortierte Entity-Selections werden nur bei Bedarf erstellt, oder wenn sie über spezifische Optionen angefordert werden.
Sortierte Entity-Selections werden in folgenden Fällen erstellt:
Ergebnis einer orderBy( ) auf eine Selection ((jeder Typ) oder ein orderBy( ) auf eine Dataclass
Ergebnis der Methode newSelection( ) mit der Option dk keep ordered
Unsortierte Entity-Selections werden in folgenden Fällen erstellt:
Ergebnis einer standardmäßigen query( ) auf eine Selection (jeder Typ) oder eine query( ) auf eine Dataclass
Ergebnis der Methode newSelection( ) ohne Option
Ergebnis einer Vergleichsmethode, unabhängig vom Typ der Input Selection: or( ), and( ), minus( )
Beachten Sie, dass sich wiederholende Entity Referenzen entfernt werden, wenn eine sortierte Entity-Selection zu einer unsortierten Entity-Selection wird.
Wollen Sie eine sortierte Entity-Selection in eine unsortierte umwandeln, müssen Sie nur eine and( ) Operation darauf anwenden, wie z.B.:
//mySel ist eine sortierte Entity-Selection mySel:=mySel.and(mySel) //mySel ist jetzt eine unsortierte Entity-Selection
4D bietet eine automatische Optimierung für ORDA Anfragen, die Entity-Selections nutzen oder Entities in Client/Server Konfigurationen laden. Diese Optimierung beschleunigt die Ausführung Ihrer 4D Anwendung, da sie die Menge an Informationen, die über das Netzwerk übertragen wird, drastisch verringert.
Zur Optimierung sind folgende Mechanismen eingebaut:
Fordert ein Client eine Entity-Selection vom Server an, "lernt" 4D automatisch, welche Attribute der Entity-Selection während Ausführen des Code gerade auf Client-Seite verwendet werden und erstellt einen entsprechenden "Optimimierungskontext". Dieser Kontext wird der Entity-Selection zugeordnet und speichert die verwendeten Attribute. Werden später andere Attribute verwendet, wird er dynamisch aktualisiert.
Nachfolgend an den Server gesendete Anfragen zur gleichen Entity-Selection verwenden automatisch wieder diesen Optimierungskontext und erhalten vom Server nur die notwendigen Attribute. Das beschleunigt die Bearbeitung. Beispiel: in einer Listbox-basierten Entity-Selection findet die Lernphase während der Anzeige der ersten Zeilen statt, was die Anzeige der nächsten Zeilen stark optimiert.
Ein vorhandener Optimierungskontext lässt sich als Eigenschaft an eine andere Entity-Selection derselben Dataclass übergeben, wodurch die Lernphase übergeben und die Anwendung beschleunigt wird (siehe unten "Eigenschaft Kontext übergeben").
Folgende Methoden weisen den Optimierungskontext der Entity-Selection Quelle automatisch der zurückgegebenen Entity- Selection zu:
$sel:=$ds.Employee.query("firstname = ab@") For each($e;$sel) $s:=$e.firstname+" "+$e.lastname+" works for "+$e.employer.name // $e.employer bezieht sich auf die Tabelle Company End for each
Dank der Optimierung erhält diese Anfrage in $sel nach der Lernphase nur Daten der verwendeten Attribute (firstname, lastname, employer, employer.name).
Die Eigenschaft context verwenden
Sie können die Vorteile der Optimierung durch die Eigenschaft context verbessern. Sie bezieht sich auf den "gelernten" Optimierungskontext für eine Entity-Selection. Sie lässt sich auch als Parameter an ORDA Methoden übergeben, die neue Entity- Selections zurückgeben, so dass Entity-Selections die verwendeten Attribute direkt vom Server anfragen und die Lernphase übernehmen.
Die gleiche Eigenschaft lässt sich auch an eine unbegrenzte Zahl von Entity-Selections in derselben Dataclass übergeben. Alle ORDA Methoden, die Entity-Selection verwalten, unterstützen die Eigenschaft context (zum Beispiel Methode dataClass.query() oder dataClass.all()). Beachten Sie jedoch, dass ein Kontext automatisch aktualisiert wird, wenn neue Attribute in anderen Teilen des Code verwendet werden. Erneutes Verwenden desselben Kontexts in unterschiedlichen Codes könnten den Kontext überladen und so dessen Effizienz beeinträchtigen.
Hinweis: Ein ähnlicher Mechanismus ist für Entities eingebaut, die geladen werden, so dass nur verwendete Attribute abgefragt werden (siehe die Methode dataClass.get()).
$sel1:=ds.Employee.query("lastname = S@";$querysettings) $data:=extractData($sel1) // In der Methode extractData wird eine Optimierung ausgelöst und dem Kontext "shortList" zugewiesen
$sel2:=ds.Employee.query("lastname = Sm@";$querysettings) $data:=extractData($sel2) // In der Methode extractData wird die dem Kontext "shortList" zugewiesene Optimierung angewandt
$sel3:=ds.Employee.query("lastname = Smith";$querysettings2) $data:=extractDetailedData($sel3) // In der Methode extractDetailedData wird eine Optimierung ausgelöst und dem Kontext "longList" zugewiesen
$sel4:=ds.Employee.query("lastname = Brown";$querysettings2) $data:=extractDetailedData($sel4) // In der Methode extractDetailedData wird die dem Kontext "longList" zugewiesene Optimierung angewandt
Listbox, die auf Entity-Selections basiert
Die Optimierung der Entity-Selection wird automatisch auf Listbox-basierte Entity-Selection in Client/Server Konfigurationen angewandt, wenn Inhalt der Listbox angezeigt und gescrollt wird. Nur die in der Listbox angezeigten Attribute werden vom Server angefragt. Wird die aktuelle Entity über die Eigenschaft Aktueller Eintrag der Listbox geladen, gibt es auch den spezifischen Kontext "Seitenmodus" (siehe Listboxen vom Typ Collection oder Entity-Selection). Er sorgt dafür, dass der ursprüngliche Kontext der Listbox nicht überladen wird, insbesondere wenn die "Seite" zusätzliche Attribute anfordert. Beachten Sie, dass der Seitenmodus nur über die Eigenschaft Aktueller Eintrag angelegt bzw. eingesetzt wird. Der Zugriff über entitySelection[index] verändert den Kontext Entity Selection.
Diese Optimierung wird auch von Anfragen genutzt, die später über Methoden, welche die Entity durchlaufen, an den Server gesendet werden. Folgende Methoden weisen automatisch den Optimierungskontext von der Entity Quelle der zurückgegebenen Entity zu:
Der folgende Code lädt z.B. die ausgewählte Entity und erlaubt das Durchlaufen der Entity-Selection. Entities werden in einem separaten Kontext geladen und der ursprüngliche Kontext der Listbox bleibt unverändert bestehen:
$myEntity:=Form.currentElement //Ausdruck aktueller Eintrag //... etwas ausführen $myEntity:=$myEntity.next() //lädt die nächste Entity mit dem gleichen Kontext
Kompatibilitätshinweis: Kontexte, die in über Open datastore hergestellten Verbindungen verarbeitet werden, können nur zwischen ähnlichen Hauptversionen von 4D verwendet werden. Zum Beispiel kann eine 4D v19.x Remote Applikation nur Kontexte eines 4D Server v19.x Datastore verwenden.
Das Objekt Entity-Selection selbst kann nicht als Objekt kopiert werden:
$myentitysel:=OB Copy(ds.Employee.all()) //gibt Null zurück
Die Eigenschaften der Entity-Selection sind dagegen aufzählbar:
ARRAY TEXT($prop;0) OB GET PROPERTY NAMES(ds.Employee.all();$prop) //$prop enthält die Namen der Entity-Selection Eigenschaften //("length", 00", "01"...)