Home Forum Nuclos Entwicklung Makros und Regeln Zugriff auf BusinessObjects mit der neuen API

Ansicht von 6 Beiträgen - 1 bis 6 (von insgesamt 6)
  • Autor
    Beiträge
  • #6142
    Matthias Haake
    Teilnehmer

    Hallo.

    Im Ticket http://support.nuclos.de/browse/NUCLOS-1430 wurde vom Support angeregt, einen Diskussion-Thread im Forum zu eröffnen.

    Thematisch geht es darum, ob und wie es zukünftig möglich sein soll, in einer Regel generisch auf unterschiedliche Entitäten zuzugreifen. Das hieße zum Beispiel, eine Regel berechnet einen Wert und kann das sowohl für Entität X als auch für Entität Y machen.

    Wie sind Eure Erfahrungen und Anwendungsfälle zu diesem Thema?

    Viele Grüße,
    Matthias

    #6143
    Matthias Haake
    Teilnehmer

    Um selbst mal ein Beispiel zum aktuellen Status Quo zu geben:

    Eine Regel berechnet Google-Maps-Links. Dazu werden Adressangaben benötigt. Diese Regel binde ich an mehrere Entitäten (z.B. Mitarbeiter, Kunde, Ansprechpartner, Lieferant, Proband, Institut, Filiale etc) – halt an alle Entitäten, die Adressinformationen besitzen.

    Die Felder mit den Adressangaben heißen in allen Entitäten identisch. D.h. die Straße steht immer im Attribut „street“ usw. Jede Entität besitzt ein Feld „streetmap“ vom Typ Text (255). Die Regel ließt nun die Adressangaben aus und generiert einen Text, der im Feld „streetmap“ gespeichert wird.

    Mit der neuen API kann man aktuell wie folgt auf BusinessObjects zugreifen:

    Mitarbeiter m = context.getBusinessObject(Mitarbeiter.class);
    m.setStreetmap(...);

    Da bringt es nichts, wenn ich diese Regel auch an die Entität „Kunde“ binde. Der Abruf „getBusinessObject“ wird nicht klappen, da Kunde nicht nach Mitarbeiter gecastet werden kann.

    Jetzt kann man
    [1] entweder eine Regel pro Entität schreiben
    oder
    [2] mit Reflections arbeiten
    oder
    [3] auf ein neues Feature warten, in dem unterschiedliche Eintitäten ein gemeinsames Interface (z.B. IAddressInformation) implementieren können

    Viele Grüße,
    Matthias

    #6144
    Matthias Haake
    Teilnehmer

    Abschließend noch ein weiteres Beispiel: Stichwort Adressetiketten

    Jeder Adresse kann über eine Klappbox ein Adressformat zugewiesen werden. Dies ist bei uns ein mehrzeiliges Textfeld, was z.B. für einen Ansprechpartner einer deutschen Firma wie folgt aussehen kann:

    ##company##
    ##formofaddress####
    |appendix##
    ##street#### |housenumber##
    ##postalcode#### |city##
    ##country##

    Dieser Ansprechpartner bekommt ein anderes Adressformat zugewiesen als ein ausländischer Lieferant, um sowohl verschiedene Adressfelder zu verwenden als auch um regionale Adressformatierungen zu beherrschen (z.B. DE: Straße + Hausnummer VS US: Hausnummer + Straße).

    Die Regel liest beim Update eines Datensatzes die Werte der Adressfelder aus und ersetzt damit die Platzhalter im Adressformat-Template. Das Resultat wird im Feld „addresstext“ der Entität abgelegt. Auch diese Regel wird idealerweise in allen Entitäten mit Adressinformationen wiederverwendet.

    Viele Grüße,
    Matthias

    #6149
    Ramin Goettlich
    Teilnehmer

    Generische getter und setter (getField(String sFieldname) und setField(String sFieldname, Object value) einzubauen, wäre eine Sache von 2 Minuten. Wir versuchen aber, Wege zu finden, die daraus entstehenden Nachteile zu umgehen. Die Nachteile sind:

    * Nuclos kann nicht erkennen, dass in Regeln Felder referenziert werden, die nicht oder nicht mehr existieren. Eine Entitätsänderung kann also Regeln zerstören, ohne dass das zunächst auffallen würde.

    * Eine automatische Anpassung von Regeln bei Umbenennungen von Feldern wird dann unmöglich.

    * Wirklich generische Regeln lassen sich damit auch nicht implementieren. Sie können vielleicht sicherstellen, dass in Ihrem Nuclet alle Adressfelder „strasse,“ „hnr“ o.ä. benannt werden – spätestens wenn Sie das Nuclet aber einem Dritten zur Verfügung stellen möchten, können Sie sich nicht mehr darauf verlassen, dass dieser Dritte derselben Konvention folgt.

    Keine Lösung für die ersten beiden Nachteile ist auch die Verwendung voll klassifizierter Strings für Feldnamen, z.B. „..“, da auch dazu ja das BUSINESSOBJEKT bekannt sein muss (und nicht generisch angegeben werden kann). Baut man den String hingegen zusammen, bleiben die Nachteile bestehen, da dann wieder keine automatische Erkennung im Sourcecode der Regel möglich ist.

    #6150
    Ramin Goettlich
    Teilnehmer

    Wir könnten eine Utils-Klasse („Unsafe“) 😉 zur Verfügung stellen, die einen Workaround bietet und die Inhalte über Reflection holt:

    Unsafe.getField(Businessobject bo, String sFieldname)
    Unsafe.setField(Businessobject bo, String sFieldname, Object o)

    Das wäre dann ein Nuclet, nicht Teil von Nuclos, und die Nutzung unterliegt der eigenen Verantwortung.

    Aber zumindest hat man einen Workaround für jetzt, auch bevor es einen zukünftig vielleicht besseren Ansatz gibt.

    #6151
    Matthias Haake
    Teilnehmer

    Vielen Dank für die Antworten. Persönlich finde ich die Interfaces am besten.

    Alternativ – aber ein bisschen aufwändiger – könnte man sich ja DTO-Klassen anlegen, die nur die gemeinsamen Felder besitzen. Die Logik-Rules würden dann ausschließlich mit den DTOs arbeiten. Für die entsprechenden Entitäten bräuchte man dann ein Mapping zwischen Entität und DTO. Das wäre in C# über Extension Methods schnell und elegant gelöst, werde in Java aber davon absehen.

    Für mich heißt das, ich setze eine statische Utilityklasse ein, die das über Reflections löst und freue mich auf die Interfaces 🙂

    Voraussetzung ist aber: Das BusinessObject lässt sich aus dem Kontext abfragen (ohne Class-Parameter). In der aktuellen Version (3.9.4) geht das noch nicht, daher kann man frühestens beim nächsten Update damit starten…

    Leider geht auch der versuchte Hack nicht (org.nuclos.server.api.eventsupport ist auch gesperrt) – muss also wirklich warten :dry:

    Field field = context.getClass().getField("busiObject");
    field.setAccessible(true);
    result = (BusinessObject)field.get(context);

Ansicht von 6 Beiträgen - 1 bis 6 (von insgesamt 6)