
Der dritte und letzte Teil einer Artikelserie zur Sprache lsFusion (Links zum
ersten und
zweiten Teil)
Es wird sich auf das physikalische Modell konzentrieren: alles, was nicht mit der Funktionalität des Systems verbunden ist, sondern mit seiner Entwicklung und Leistungsoptimierung verbunden ist, wenn zu viele Daten vorhanden sind.
Dieser Artikel ist, wie die vorherigen, nicht sehr gut für unterhaltsames Lesen geeignet, aber im Gegensatz zu den anderen gibt es mehr technische Details und „heiße“ Themen (wie Tippen oder Metaprogrammieren), und dieser Artikel gibt einen Teil der Antworten auf die Frage, wie ist das alles? arbeitet innen.
In diesem Artikel verzichten wir auf ein Bild (es gibt keinen solchen Stapel), aber wir erstellen ein Inhaltsverzeichnis, wie in den vorherigen Artikeln gefordert:
Artikelidentifikation
Wenn das Projekt aus mehreren kleinen Dateien besteht, treten normalerweise keine Probleme bei der Benennung von Elementen auf. Alle Namen sind in Sicht und leicht genug, um sicherzustellen, dass sie sich nicht überschneiden. Wenn das Projekt im Gegenteil aus vielen Modulen besteht, die von einer großen Anzahl unterschiedlicher Personen entwickelt wurden, und Abstraktionen in diesen Modulen von einer Domänendomäne, werden Namenskonflikte viel wahrscheinlicher. LsFusion verfügt über zwei Mechanismen zur Lösung dieser Probleme:
- Namespaces - Trennung eines Namens in vollständig und kurz und die Möglichkeit, beim Zugriff auf ein Element nur einen kurzen Namen zu verwenden
- Explizite Typisierung (genauer gesagt Funktionsüberladung) - die Möglichkeit, Eigenschaften (und Aktionen) auf dieselbe Weise zu benennen und dann beim Zugriff abhängig von den Argumentklassen automatisch zu bestimmen, für welche Eigenschaft der Aufruf bestimmt ist
Namespaces
Jedes komplexe Projekt besteht normalerweise aus einer großen Anzahl von Elementen, die benannt werden müssen. Wenn sich Domänendomänen überschneiden, muss häufig derselbe Name in verschiedenen Kontexten verwendet werden. Zum Beispiel haben wir den Namen einer Klasse oder eines Formulars Rechnung (Rechnung) und möchten diesen Namen in verschiedenen Funktionsblöcken verwenden, zum Beispiel: Kauf (Kauf), Verkauf (Verkauf), Rückgabe (PurchaseReturn), Rückgabe (SaleReturn). Es ist klar, dass Klassen / Formulare als PurchaseInvoice, SaleInvoice usw. bezeichnet werden können. Aber erstens werden solche Namen an sich zu sperrig sein. Und zweitens gehen Aufrufe in einem Funktionsblock in der Regel zu den Elementen desselben Funktionsblocks, was bedeutet, dass bei der Entwicklung beispielsweise des Funktionsblocks "Kaufen" aus einer ständigen Wiederholung des Wortes "Kaufen" einfach die Augen kräuseln. Um dies zu verhindern, verfügt die Plattform über ein Konzept wie einen Namespace. Es funktioniert wie folgt:
- Jedes Element auf der Plattform wird in einem Namespace erstellt
- Wenn beim Erstellen eines Elements auf andere Elemente verwiesen wird, haben Elemente, die im selben Namespace erstellt wurden, Vorrang
Namespaces in der aktuellen Sprachversion werden für das gesamte Modul unmittelbar im Modulheader festgelegt. Wenn kein Namespace angegeben ist, wird dieser standardmäßig implizit mit einem Namen erstellt, der dem Modulnamen entspricht. Wenn Sie über einen Namespace ohne Priorität auf ein Element zugreifen müssen, können Sie dies tun, indem Sie den vollständigen Namen des Elements angeben (z. B. Sale.Invoice).
Explizite Eingabe
Namespaces sind wichtig, aber nicht die einzige Möglichkeit, Code kürzer und lesbarer zu machen. Darüber hinaus können bei der Suche nach Eigenschaften (und Aktionen) auch die Klassen von Argumenten berücksichtigt werden, die bei der Eingabe an sie übergeben wurden. Also zum Beispiel:
Hier kann sich natürlich die Frage stellen: Was passiert, wenn der Namespace der gewünschten Eigenschaft keine Priorität hat, aber besser für Klassen geeignet ist? Tatsächlich ist der allgemeine Suchalgorithmus ziemlich kompliziert (die vollständige Beschreibung finden Sie
hier ), und es gibt viele solcher „mehrdeutigen“ Fälle. Im Falle von Unsicherheit wird daher empfohlen, entweder Namespaces / Klassen der gewünschten Eigenschaft explizit anzugeben oder die IDE zu überprüfen (mithilfe von Zur Deklaration gehen -). STRG + B) dass die gefundene Eigenschaft genau das ist, was gemeint war.
Es ist auch erwähnenswert, dass eine explizite Eingabe in lsFusion im Allgemeinen nicht erforderlich ist. Parameterklassen können weggelassen werden. Wenn die Plattform über genügend Informationen verfügt, um die gewünschte Eigenschaft zu finden, wird dies der Fall sein. Andererseits wird in wirklich komplexen Projekten immer noch empfohlen, Parameterklassen explizit festzulegen, nicht nur unter dem Gesichtspunkt der Kürze des Codes, sondern auch unter dem Gesichtspunkt verschiedener zusätzlicher Funktionen, wie z. B. frühzeitige Fehlerdiagnose, intelligente automatische Vervollständigung über die IDE usw. Wir hatten umfangreiche Erfahrung sowohl mit impliziter Eingabe (die ersten 5 Jahre) als auch mit expliziter (verbleibender Zeit), und ich muss sagen, dass die Zeiten der impliziten Eingabe jetzt mit einem Schauder in Erinnerung bleiben (obwohl es vielleicht nur „wir wussten nicht, wie man es kocht“).
Modularität
Modularität ist eine der wichtigsten Eigenschaften des Systems, die es ermöglicht, die Erweiterbarkeit, die Wiederverwendung von Code sowie die effektive Interaktion des Entwicklungsteams sicherzustellen.
LsFusion bietet Modularität mit den folgenden zwei Mechanismen:
- Erweiterungen - Die Möglichkeit, die Elemente des Systems nach ihrer Erstellung zu erweitern (zu ändern).
- Module - die Möglichkeit, einige Funktionen für die weitere Wiederverwendung zu gruppieren.
Erweiterungen
lsFusion unterstützt die Möglichkeit, Klassen und Formen sowie Eigenschaften und Aktionen durch den im ersten Artikel beschriebenen Polymorphismusmechanismus zu erweitern.
Wir stellen außerdem fest, dass fast alle anderen Plattformdesigns (z. B. Navigator, Formularentwurf) per Definition erweiterbar sind, daher gibt es für sie keine separate Erweiterungslogik.
Module
Ein Modul ist ein funktional vollständiger Teil eines Projekts. In der aktuellen Version von lsFusion ist ein Modul eine separate Datei, die aus dem Header und dem Hauptteil eines Moduls besteht. Der Titel des Moduls besteht wiederum aus: dem Namen des Moduls sowie gegebenenfalls einer Liste der verwendeten Module und dem Namen des Namespace dieses Moduls. Der Hauptteil des Moduls besteht aus Deklarationen und / oder Erweiterungen von Systemelementen: Eigenschaften, Aktionen, Einschränkungen, Formulare, Metacodes usw.
In der Regel verwenden Module Elemente aus anderen Modulen, um ihre eigenen Elemente zu deklarieren / vorhandene Elemente zu erweitern. Wenn Modul B Elemente aus Modul A verwendet, muss dementsprechend in Modul B angegeben werden, dass es von A abhängt.
Aufgrund ihrer Abhängigkeiten sind alle Module im Projekt in einer bestimmten Reihenfolge angeordnet, in der sie initialisiert werden (diese Reihenfolge spielt eine wichtige Rolle bei Verwendung des oben genannten Erweiterungsmechanismus). Wenn Modul B von Modul A abhängt, erfolgt die Initialisierung von Modul A garantiert früher als die Initialisierung von Modul B. Zyklische Abhängigkeiten zwischen den Modulen im Projekt sind nicht zulässig.
Abhängigkeiten zwischen Modulen sind transitiv. Das heißt, wenn Modul C von Modul B und Modul B von Modul A abhängt, wird davon ausgegangen, dass Modul C auch von Modul A abhängt.
Jedes Modul hängt immer automatisch vom Systemmodul System ab, unabhängig davon, ob es explizit angegeben ist oder nicht.
Metaprogrammierung
Metaprogrammierung ist eine Art der Programmierung, die mit dem Schreiben von Programmcode verbunden ist und als Ergebnis einen anderen Programmcode generiert. LsFusion verwendet sogenannte Metacodes für die Metaprogrammierung.
Der Metacode besteht aus:
- Metacode-Name
- Metacode-Parameter
- Hauptteil eines Metacodes - ein Codeblock, der aus Deklarationen und / oder Erweiterungen von Systemelementen (Eigenschaften, Aktionen, Ereignisse, andere Metacodes usw.) besteht.
Dementsprechend bereitet die Plattform den Code vor Beginn der Hauptverarbeitung vor und ersetzt alle Verwendungen von Metacodes durch die Körper dieser Metacodes. In diesem Fall werden alle in Bezeichnern / Zeichenfolgenliteralen verwendeten Metacode-Parameter durch die an diesen Metacode übergebenen Argumente ersetzt:
Ankündigung:
Verwendung:
Resultierender Code:
Neben dem einfachen Ersetzen von Metacode-Parametern können Sie diese Parameter auch mit vorhandenen Bezeichnern / Zeichenfolgenliteralen (oder miteinander) kombinieren, zum Beispiel:
Ankündigung:
Verwendung:
Resultierender Code:
Metacodes sind Makros in C sehr ähnlich, funktionieren jedoch im Gegensatz zu letzteren nicht auf Textebene (sie können beispielsweise keine Schlüsselwörter im Parameter übergeben), sondern nur auf der Ebene von Bezeichnern / Zeichenfolgenliteralen (insbesondere diese Einschränkung ermöglicht dies) Parsen des Metacode-Körpers in der IDE).
In lsFusion lösen Metacodes ähnliche Probleme wie Generika in Java (Übergabe von Klassen als Parameter) und Lambda in FPs (Übergabe von Funktionen als Parameter), tun dies jedoch nicht sehr gut. Auf der anderen Seite tun sie dies jedoch in einem viel allgemeineren Fall (z. B. mit der Möglichkeit, Bezeichner zu kombinieren, in syntaktischen Konstruktionen zu verwenden - Formen, Designs, Navigator usw.).
Beachten Sie, dass die "Bereitstellung" von Metacodes nicht nur auf der Plattform selbst, sondern auch in der IDE unterstützt wird. In der IDE gibt es also einen speziellen Modus "Meta aktivieren", der den resultierenden Code direkt in den Quellen generiert und es diesem generierten Code ermöglicht, an der Suche nach Verwendungen, der automatischen Vervollständigung usw. teilzunehmen. In diesem Fall aktualisiert die IDE automatisch alle Verwendungen dieses Metacodes, wenn sich der Hauptteil des Metacodes ändert.

Außerdem können Metacodes nicht nur zur automatischen, sondern auch zur manuellen Codegenerierung (als Vorlagen) verwendet werden. Zu diesem Zweck reicht es aus, @@ anstelle eines @ zu schreiben. Unmittelbar nach der vollständigen Eingabe der Metacode-Verwendungszeichenfolge (bis zum Semikolon) ersetzt die IDE diese Metacode-Verwendung durch den von diesem Metacode generierten Code:

Integration
Die Integration umfasst alles, was mit der Interaktion des lsFusion-Systems mit anderen Systemen zusammenhängt. Unter dem Gesichtspunkt der Richtung dieser Interaktion kann die Integration unterteilt werden in:
- Zugriff auf das lsFusion-System von einem anderen System aus.
- Zugriff vom lsFusion-System auf ein anderes System.
Aus Sicht des physikalischen Modells kann die Integration unterteilt werden in:
- Interaktion mit Systemen, die in derselben Umgebung wie das lsFusion-System ausgeführt werden (dh in der Java Virtual Machine (JVM) des lsFusion-Servers und / oder unter Verwendung desselben SQL-Servers wie das lsFusion-System).
- Interaktion mit Remote-Systemen über Netzwerkprotokolle.
Dementsprechend werden die ersten Systeme als intern bezeichnet, das zweite als extern.
Somit gibt es vier verschiedene Arten der Integration in die Plattform:
- Appell an ein externes System
- Berufung von einem externen System
- Appell an das interne System
- Berufung vom internen System
Appell an ein externes System
Der Zugriff auf externe Systeme in lsFusion wird in den meisten Fällen mit dem speziellen EXTERNAL-Operator implementiert. Dieser Operator führt den angegebenen Code in der Sprache / im Paradigma des angegebenen externen Systems aus. Darüber hinaus können Sie mit diesem Operator Objekte primitiver Typen als Parameter eines solchen Aufrufs übertragen und die Ergebnisse des Aufrufs in die angegebenen Eigenschaften (ohne Parameter) schreiben.
Derzeit unterstützt die Plattform die folgenden Arten von Interaktionen / externen Systemen:
HTTP - Führt eine http-Anforderung von einem Webserver aus.Für diese Art der Interaktion müssen Sie eine Abfragezeichenfolge (URL) angeben, die gleichzeitig sowohl die Serveradresse als auch die Anforderung bestimmt, die ausgeführt werden muss. Parameter können sowohl in der Abfragezeile (um auf den Parameter zuzugreifen, werden das Sonderzeichen $ und die Nummer dieses Parameters ab 1) als auch in dessen Body (BODY) übertragen. Es wird davon ausgegangen, dass alle Parameter, die nicht in der Abfragezeichenfolge verwendet werden, an BODY übergeben werden. Wenn der BODY mehr als einen Parameter enthält, wird der BODY-Inhaltstyp während der Übertragung auf mehrteilig / gemischt gesetzt, und die Parameter werden als Komponenten dieses BODY übertragen.
Bei der Verarbeitung von Parametern von Dateiklassen (FILE, PDFFILE usw.) in BODY wird der Inhaltstyp des Parameters abhängig von der Dateierweiterung (gemäß der folgenden
Tabelle ) bestimmt. Wenn sich die Dateierweiterung nicht in dieser Tabelle befindet, wird der Inhaltstyp auf application / <Dateierweiterung> festgelegt.
Bei Bedarf können Sie mit der Sonderoption (HEADERS) die Header der ausgeführten Anfrage setzen. Dazu müssen Sie eine Eigenschaft mit genau einem Parameter der Zeichenfolgenklasse angeben, in der der Titel gespeichert wird, und den Wert der Zeichenfolgenklasse, in der der Wert dieses Headers gespeichert wird.
Das Ergebnis der http-Anforderung wird auf die gleiche Weise wie seine Parameter verarbeitet, nur in die entgegengesetzte Richtung: Wenn beispielsweise der Inhaltstyp des Ergebnisses entweder in der folgenden
Tabelle vorhanden ist oder der Anwendung / * entspricht, wird davon ausgegangen, dass das erhaltene Ergebnis eine Datei ist und in eine Eigenschaft mit dem Wert FILE geschrieben werden sollte . Die Header des Ergebnisses der http-Anfrage werden analog zu den Headern dieser Anfrage selbst verarbeitet (mit dem einzigen Unterschied, dass die Option HEADERSTO heißt, nicht HEADERS).
SQL - Ausführen eines SQL Server-Befehls.Für diese Art der Interaktion werden die Verbindungszeichenfolge und die auszuführenden SQL-Befehle angegeben. Parameter können sowohl in der Verbindungszeichenfolge als auch im SQL-Befehl übergeben werden. Für den Zugriff auf den Parameter werden das Sonderzeichen $ und die Nummer dieses Parameters verwendet (ab 1).
Parameter von Dateiklassen (FILE, PDFFILE usw.) können nur im SQL-Befehl verwendet werden. Wenn einer der Parameter während der Ausführung eine TABLE-Datei ist (TABLEFILE oder FILE mit der Tabellenerweiterung), wird dieser Parameter auch in diesem Fall als Tabelle betrachtet:
- Vor dem Ausführen des SQL-Befehls wird der Wert jedes dieser Parameter in einer temporären Tabelle auf den Server geladen
- Beim Ersetzen von Parametern wird nicht der Parameterwert selbst ersetzt, sondern der Name der erstellten temporären Tabelle
Die Ausführungsergebnisse sind: für DML-Abfragen - Zahlen, die der Anzahl der verarbeiteten Datensätze entsprechen, für SELECT-Abfragen - Dateien im TABLE-Format (FILE mit der Tabellenerweiterung), die die Ergebnisse dieser Abfragen enthalten. Die Reihenfolge dieser Ergebnisse stimmt mit der Ausführungsreihenfolge der entsprechenden Abfragen im SQL-Befehl überein.
LSF - ein Aktionsaufruf eines anderen lsFusion-Servers.Für diese Art der Interaktion wird die Verbindungszeichenfolge zum lsFusion-Server (oder dessen Webserver, falls vorhanden) festgelegt, die auszuführende Aktion sowie eine Liste von Eigenschaften (ohne Parameter), in deren Werte die Ergebnisse des Aufrufs geschrieben werden. Die zu übertragenden Parameter müssen in Anzahl und Klasse mit den Parametern der ausgeführten Aktion übereinstimmen.
Die Methode zum Festlegen der Aktion in dieser Art von Interaktion stimmt vollständig mit der Methode zum Festlegen der Aktion beim Zugriff von einem externen System aus überein (Informationen zu dieser Art von Zugriff finden Sie im nächsten Abschnitt).
Standardmäßig wird diese Art der Interaktion mithilfe des HTTP-Protokolls mithilfe der entsprechenden Schnittstellen für den Zugriff auf / von einem externen System implementiert.
Für den Fall, dass Sie mit einem anderen als dem oben genannten Protokoll auf das System zugreifen müssen, können Sie dies jederzeit tun, indem Sie eine Aktion in Java erstellen und diesen Aufruf dort implementieren (mehr dazu später im Abschnitt „Zugriff auf interne Systeme“).
Berufung von einem externen System
Die Plattform ermöglicht externen Systemen den Zugriff auf das auf lsFusion entwickelte System mithilfe des HTTP-Netzwerkprotokolls. Die Schnittstelle dieser Interaktion besteht darin, eine Aktion mit den angegebenen Parametern aufzurufen und bei Bedarf die Werte einiger Eigenschaften (ohne Parameter) als Ergebnis zurückzugeben. Es wird angenommen, dass alle Objekte von Parametern und Ergebnissen Objekte primitiver Typen sind.
Die aufgerufene Aktion kann auf drei Arten eingestellt werden:
- / exec? action = <Aktionsname> - Legt den Namen der aufgerufenen Aktion fest.
- / eval? script = <code> - Legt den Code in lsFusion fest. Es wird angenommen, dass in diesem Code eine Deklaration einer Aktion mit dem Namen run vorhanden ist. Diese Aktion wird aufgerufen. Wenn der Skriptparameter nicht angegeben wird, wird angenommen, dass der Code als erster BODY-Parameter übergeben wird.
- / eval / action? script = <Aktionscode> - Legt den Aktionscode in lsFusion fest. Um auf die Parameter zuzugreifen, können Sie das Sonderzeichen $ und die Parameternummer (ab 1) verwenden.
Wenn im zweiten und dritten Fall der Skriptparameter nicht angegeben wird, wird angenommen, dass der Code vom ersten BODY-Parameter übergeben wird.
Die Verarbeitung von Parametern und Ergebnissen ist symmetrisch zum Zugriff auf externe Systeme über das HTTP-Protokoll (mit dem einzigen Unterschied, dass die Parameter als Ergebnisse verarbeitet werden und im Gegenteil, die Ergebnisse als Parameter verarbeitet werden), sodass wir uns nicht viel wiederholen werden.
Zum Beispiel, wenn wir eine Aktion haben:
Dann können Sie mit einer POST-Anfrage darauf zugreifen, die:
- URL - http: // server_address / exec? Action = importOrder & p = 123 & p = 2019-01-01
- BODY - JSON-Datei mit Abfragezeichenfolgen
Beispiel für einen Python-Aufruf import json import requests from requests_toolbelt.multipart import decoder lsfCode = ("run(INTEGER no, DATE date, FILE detail) {\n" " NEW o = FOrder {\n" " no(o) <- no;\n" " date(o) <- date;\n" " LOCAL detailId = INTEGER (INTEGER);\n" " LOCAL detailQuantity = INTEGER (INTEGER);\n" " IMPORT JSON FROM detail TO detailId, detailQuantity;\n" " FOR imported(INTEGER i) DO {\n" " NEW od = FOrderDetail {\n" " id(od) <- detailId(i);\n" " quantity(od) <- detailQuantity(i);\n" " price(od) <- 5;\n" " order(od) <- o;\n" " }\n" " }\n" " APPLY;\n" " EXPORT JSON FROM price = price(FOrderDetail od), id = id(od) WHERE order(od) == o;\n" " EXPORT FROM orderPrice(o), exportFile();\n" " }\n" "}") order_no = 354 order_date = '10.10.2017' order_details = [dict(id=1, quantity=10), dict(id=2, quantity=15), dict(id=5, quantity=4), dict(id=10, quantity=18), dict(id=11, quantity=1), dict(id=12, quantity=3)] order_json = json.dumps(order_details) url = 'http://localhost:7651/eval' payload = {'script': lsfCode, 'no': str(order_no), 'date': order_date, 'detail': ('order.json', order_json, 'text/json')} response = requests.post(url, files=payload) multipart_data = decoder.MultipartDecoder.from_response(response) sum_part, json_part = multipart_data.parts sum = int(sum_part.text) data = json.loads(json_part.text)
Appell an das interne System
Es gibt zwei Arten der internen Interaktion:
Java-InteroperabilitätMit dieser Art der Interaktion können Sie Java-Code innerhalb des JVM-lsFusion-Servers aufrufen. Dazu müssen Sie:
- Stellen Sie sicher, dass auf die kompilierte Java-Klasse im Klassenpfad des Anwendungsservers zugegriffen werden kann. Es ist auch erforderlich, dass diese Klasse lsfusion.server.physics.dev.integration.internal.to.InternalAction erbt.
Java-Klassenbeispiel import lsfusion.server.data.sql.exception.SQLHandledException; import lsfusion.server.language.ScriptingErrorLog; import lsfusion.server.language.ScriptingLogicsModule; import lsfusion.server.logics.action.controller.context.ExecutionContext; import lsfusion.server.logics.classes.ValueClass; import lsfusion.server.logics.property.classes.ClassPropertyInterface; import lsfusion.server.physics.dev.integration.internal.to.InternalAction; import java.math.BigInteger; import java.sql.SQLException; public class CalculateGCD extends InternalAction { public CalculateGCD(ScriptingLogicsModule LM, ValueClass... classes) { super(LM, classes); } @Override protected void executeInternal(ExecutionContext<ClassPropertyInterface> context) throws SQLException, SQLHandledException { BigInteger b1 = BigInteger.valueOf((Integer)getParam(0, context)); BigInteger b2 = BigInteger.valueOf((Integer)getParam(1, context)); BigInteger gcd = b1.gcd(b2); try { findProperty("gcd[]").change(gcd.intValue(), context); } catch (ScriptingErrorLog.SemanticErrorException ignored) { } } }
- Registrieren einer Aktion mit dem speziellen internen Anrufbetreiber (INTERN)
- Eine registrierte Aktion kann wie jede andere über den Anrufbetreiber aufgerufen werden. In diesem Fall wird die Methode executeInternal (lsfusion.server.logics.action.controller.context.ExecutionContext context) der angegebenen Java-Klasse ausgeführt.
SQL-InteraktionMit dieser Art der Interaktion können Sie auf die Objekte / Syntaxkonstrukte des SQL-Servers zugreifen, die vom entwickelten lsFusion-System verwendet werden. Um diese Art der Interaktion in der Plattform zu implementieren, wird ein spezieller Operator verwendet - FORMEL. Mit diesem Operator können Sie eine Eigenschaft erstellen, die eine Formel in der SQL-Sprache auswertet. Die Formel wird in Form einer Zeichenfolge festgelegt, in der das Sonderzeichen $ und die Nummer dieses Parameters für den Zugriff auf den Parameter verwendet werden (ab 1). Dementsprechend ist die Anzahl der Parameter der erhaltenen Eigenschaft gleich dem Maximum der Anzahl der verwendeten Parameter.
Es wird empfohlen, diesen Operator nur in Fällen zu verwenden, in denen die Aufgabe nicht mit Hilfe anderer Operatoren gelöst werden kann oder wenn garantiert ist, welche spezifischen SQL-Server verwendet werden können oder die verwendeten Syntaxkonstrukte einem der neuesten SQL-Standards entsprechen.
Berufung vom internen System
Alles ist symmetrisch zur Attraktivität des internen Systems. Es gibt zwei Arten der Interaktion:
Java-InteroperabilitätIm Rahmen dieser Art der Interaktion kann das interne System direkt auf die Java-Elemente des lsFusion-Systems zugreifen (wie normale Java-Objekte). Auf diese Weise können Sie dieselben Vorgänge wie bei der Verwendung von Netzwerkprotokollen ausführen, gleichzeitig jedoch einen erheblichen Aufwand für eine solche Interaktion vermeiden (z. B. Serialisierung von Parametern / Deserialisierung des Ergebnisses usw.). Darüber hinaus ist diese Kommunikationsmethode viel bequemer und effizienter, wenn die Interaktion sehr eng ist (dh während der Ausführung eines Vorgangs ist ein ständiger Kontakt in beide Richtungen erforderlich - vom lsFusion-System zu einem anderen System und umgekehrt) und / oder der Zugriff auf bestimmte Plattformknoten erforderlich ist.
, Java- lsFusion- , , Java . :
- lsFusion ( ), « » , « » ( lsfusion.server.physics.dev.integration.internal.to.InternalAction, , , ).
- , lsFusion , Spring bean', - , dependency injection ( bean businessLogics).
Java- import lsfusion.server.data.sql.exception.SQLHandledException; import lsfusion.server.data.value.DataObject; import lsfusion.server.language.ScriptingErrorLog; import lsfusion.server.language.ScriptingLogicsModule; import lsfusion.server.logics.action.controller.context.ExecutionContext; import lsfusion.server.logics.classes.ValueClass; import lsfusion.server.logics.property.classes.ClassPropertyInterface; import lsfusion.server.physics.dev.integration.internal.to.InternalAction; import java.math.BigInteger; import java.sql.SQLException; public class CalculateGCDObject extends InternalAction { public CalculateGCDObject(ScriptingLogicsModule LM, ValueClass... classes) { super(LM, classes); } @Override protected void executeInternal(ExecutionContext<ClassPropertyInterface> context) throws SQLException, SQLHandledException { try { DataObject calculation = (DataObject)getParamValue(0, context); BigInteger a = BigInteger.valueOf((Integer)findProperty("a").read(context, calculation)); BigInteger b = BigInteger.valueOf((Integer)findProperty("b").read(context, calculation)); BigInteger gcd = a.gcd(b); findProperty("gcd[Calculation]").change(gcd.intValue(), context, calculation); } catch (ScriptingErrorLog.SemanticErrorException ignored) { } } }
SQL-Interaktion Beachten Sie, dass eine solche direkte Interaktion (jedoch schreibgeschützt) besonders praktisch für die Integration in verschiedene OLAP-Systeme ist, bei denen der gesamte Prozess mit minimalem Aufwand ausgeführt werden sollte.SQL- lsFusion- ( , , SQL-), , lsFusion-, SQL-. , , ( / ), (, , — , ..), . lsFusion- , , .
Die Migration
. , , , - . , «» , - . , migration.script, classpath , , . :
Die Migration besteht aus Blöcken, die die Änderungen beschreiben, die in der angegebenen Version der Datenbankstruktur vorgenommen wurden. Beim Starten des Servers werden alle Änderungen aus der Migrationsdatei angewendet, deren Version höher ist als die in der Datenbank gespeicherte Version. Änderungen werden entsprechend der Version von einer kleineren Version zu einer größeren Version angewendet. Wenn die Datenbankstruktur erfolgreich geändert wurde, wird die maximale Version aller angewendeten Blöcke als aktuelle in die Datenbank geschrieben. Die Syntax für die Beschreibung jedes Blocks lautet wie folgt: V< > { 1 ... N }
Es gibt wiederum folgende Arten von Änderungen:Für die Migration von Benutzerdaten sind nur die ersten drei Arten von Änderungen relevant (Änderungen an primären Eigenschaften, Klassen, statischen Objekten). Die verbleibenden vier Arten von Änderungen sind erforderlich:- für die Metadatenmigration (Sicherheitsrichtlinien, Tabelleneinstellungen usw.)
- ( ).
, , .
, IDE. , , Change migration file ( ), IDE .
, . , , : , , , .. lsFusion ( , 'abc'), , :
ServerResourceBundle.properties:
scheduler.script.scheduled.task.detail=Script scheduler.constraint.script.and.action=In the scheduler task property and script cannot be selected at the same time scheduler.form.scheduled.task=Tasks
ServerResourceBundle_ru.properties
scheduler.script.scheduled.task.detail= scheduler.constraint.script.and.action= scheduler.form.scheduled.task=
, , - . , , , .
: . , — . ( - ), , , :
- . ( , ), , , .
- . , , .
- . / , . «» .
. , . , , ( ). , .
, , NULL
,
Über das Gleichgewicht zwischen Schreiben und Lesen in Datenbanken ist es meiner Meinung nach wenig sinnvoll, hier ausführlich darauf einzugehen.Indizes
Wenn Sie einen Index nach Eigenschaften erstellen, können Sie alle Werte dieser Eigenschaft in geordneter Weise in der Datenbank speichern. Dementsprechend wird der Index jedes Mal aktualisiert, wenn sich der Wert der indizierten Eigenschaft ändert. Dank des Index können Sie beispielsweise, wenn beispielsweise nach indizierten Eigenschaften gefiltert wird, sehr schnell die erforderlichen Objekte finden, anstatt alle vorhandenen Objekte im System anzuzeigen.Es können nur materialisierte Eigenschaften indiziert werden (aus dem obigen Abschnitt).Ein Index kann auch auf mehreren Eigenschaften gleichzeitig erstellt werden (dies ist effektiv, wenn beispielsweise diese verschiedenen Eigenschaften sofort gefiltert werden). Darüber hinaus können Eigenschaftsparameter in einen solchen zusammengesetzten Index aufgenommen werden. Wenn die angegebenen Eigenschaften in verschiedenen Tabellen gespeichert sind, führt ein Versuch, den Index zu erstellen, zu dem entsprechenden Fehler.Tabellen
lsFusion . , , , . key0, key1, ..., keyN, (, — ). , .
, .
, . , . , , , «» ( , , ).
, , . .
, , . , , - .
, , , (, ), , , , .
Fazit
: « , ». , , , / lsFusion , , . — .
, , . , , , , , . , , , , , .
: « ...?», , , , tutorial'.