enhancement
major
minor
major
minor
minor
#29894
Commit einer geänderten Annotation loggt ERROR mit Stacktrace, wenn der alte Wert eines abgeleiteten Attributs (z.B. options) nicht mehr instanziierbar ist
Problem
Gefunden in einer Anwendung (E-Home, 8.0.0-alpha10): Die <options>-Annotation eines Attributs (OptionsByExpression mit dem TL-Script-Aufruf simulationFollowerOptions($f, "device")) wurde von einer früheren Entwicklungsversion des Modells in der Datenbank gespeichert. Später hat sich die Stelligkeit der Script-Funktion geändert. Beim nächsten Start ersetzt die automatische Modell-Aktualisierung die Annotation korrekt, beim Commit erscheint aber pro betroffenem Attribut:
ERROR Failed to access old value of column 'options: Void' ... At most 1 argument(s) expected in: simulationFollowerOptions($f, "device")
mit vollem Stacktrace. Der Start läuft weiter und die neue Annotation ist wirksam; ein Betreiber sieht trotzdem einen ERROR für eine korrekte Aktualisierung.
Ursache
Der Fehler entsteht nicht in der Modell-Aktualisierung, sondern beim Aufbau des Änderungs-Events des Commits. DBKnowledgeItem.getChange() berechnet alten und neuen Wert aller Attribute der Tabelle, auch der abgeleiteten ComputedMOAttribute`s ohne Datenbankspalte. `options ist ein solches Attribut (ElementMeta.xml, CachedComputedAttributeStorage mit TLOptionsFactory): Sein Wert ist der aus der TLOptions-Annotation erzeugte Generator. Für den alten Wert wird daher der Generator der alten Annotation gebaut, was an der geänderten Stelligkeit scheitert; getOldValue() loggt das seit #29075 als ERROR. Die gespeicherte Annotation selbst lässt sich weiterhin lesen.
Lösung
DBKnowledgeItem.getChange() übergeht bei der Erzeugung und Änderung eines Objekts Attribute ohne Datenbank-Abbildung (leeres getDbMapping(), also berechnete/abgeleitete Werte), sofern sie keine Schlüsselattribute sind. Ihre Werte werden für das Event weder alt noch neu berechnet.
- Die Änderung ist im Event weiterhin sichtbar, über die Spalte, aus der der Wert abgeleitet ist (hier annotations).
- Aus der Datenbank gelesene Events (andere Cluster-Knoten, Historie) enthalten solche Attribute ohnehin nicht; lokale und entfernte Events werden damit gleich.
- Nebeneffekt: Beim Commit werden keine abgeleiteten Werte (z.B. Generatoren, Constraints, Default-Provider der Modellattribute) mehr nur für den Event-Vergleich instanziiert.
Das Lösch-Event eines Objekts enthält die berechneten Werte weiterhin, denn nach dem Commit lassen sie sich aus dem gelöschten Objekt nicht mehr berechnen. Kann ein solcher Wert nicht berechnet werden, wird das ohne Stacktrace als INFO protokolliert und der Wert ist im Event null; ein Fehler beim Lesen einer gespeicherten Spalte bleibt ein ERROR (#29075).