enhancement
major
minor
major
minor
major
#29681
TL-Script modifiedRevision() berücksichtigt Referenz- und Übersetzungsänderungen; Attribut-Storages "touchen" das Besitzerobjekt nicht mehr
Problem
Die TL-Script-Funktion modifiedRevision() ist dokumentiert als "die Revision, in der das Objekt zuletzt geändert wurde". Ein abgeleitetes Attribut darüber (z.B. changeDate = modifiedRevision().date) bewegte sich aber nicht, wenn sich nur Referenzen des Objekts änderten.
In der TL-Development-App (Snapshot-Build 42) setzte ein "Annehmen" an einem Ticket status (einfache Referenz) und ergänzte assignees (mehrfache Referenz). "Geändert" blieb auf dem alten Zeitpunkt stehen, auch nach einem Reload. Erst das Speichern der Zusammenfassung (I18N-String) bewegte den Wert.
Ursache
modifiedRevision() lieferte die letzte Revision der eigenen Tabellenzeile des Objekts. Die Storages von Referenzen (SingletonLinkStorage, SetStorage, …) schreiben nur Link-Zeilen und berühren die Besitzerzeile nicht.
Inkonsistent dazu riefen I18NAttributeStorage, I18NStructuredTextAttributeStorage und StructuredTextAttributeStorage owner.tTouch() auf, damit der Lucene-Index den Besitzer neu indiziert. Jeder solche Touch schreibt eine komplette neue Version der Hauptzeile des Objekts, nur um die Revision zu verschieben – Speicherverschwendung. Diesen Touch auf alle Storages auszuweiten ist deshalb keine Lösung.
Lösung
modifiedRevision()
modifiedRevision(obj) liefert die Revision der letzten Änderung irgendeines gespeicherten Attributs von obj, inklusive Referenzen in Link-Tabellen und Übersetzungen. Kompositionen:
- Teile in einer Link-Tabelle (Standard): Hinzufügen oder Entfernen eines Teils ist eine Änderung des Containers, eine Änderung innerhalb eines Teils nicht.
- Teile, die ihren Container in der eigenen Tabellenzeile speichern: Jede Änderung eines solchen Teils zählt auch als Änderung des Containers (auch Umsortieren und Verschieben zwischen zwei Referenzen desselben Containers).
Für ganze Kompositionsbäume gibt es changeLog(obj, 1, true).
Berechnet wird das Maximum aus der Revision der eigenen Zeile und, je Tabelle, in der Attribute des Typs Werte speichern (beschrieben durch die AssociationStorageDescriptor`s der `SeparateTableStorage`s), dem jüngsten Anlegen bzw. Entfernen einer Zeile des Objekts: eine indizierte Aggregat-Abfrage je Tabelle, unabhängig von der Länge der Historie. Java-Einstiegspunkt ist `com.top_logic.element.changelog.LastChangeRevision#of(TLObject).
Die Java-Methoden TLObject#tLastModificationDate(), tLastModificationTime(), tLastModifier() sowie das Lebenszyklus-Attribut "modified" bleiben unverändert (nur die eigene Zeile des Objekts); ihre Dokumentation verweist auf modifiedRevision(). Die Hilfe von modifiedRevision() erläutert den Bezug zu diesen Methoden.
Kein Touch mehr
- I18NAttributeStorage ist eine SeparateTableStorage mit Storage-Deskriptor. Änderungslog und modifiedRevision() ordnen Übersetzungszeilen damit dem Besitzer zu.
- Der Lucene-Indexdienst indiziert bei geänderten Zeilen separater Storage-Tabellen (Übersetzungen, Structured-Text-Bilder, Link-Tabellen) den Besitzer neu (ChangedValueOwners, Seam DefaultIndexingService#keysToIndex). Damit ist der Volltextindex auch nach reinen Referenzänderungen aktuell.
- Die tTouch()-Aufrufe in I18NAttributeStorage, I18NStructuredTextAttributeStorage und StructuredTextAttributeStorage entfallen.
Folge: Das allgemeine Änderungsdatum/der Änderer eines Objekts (Zeilenebene, z.B. Wrapper.getModified()) bewegt sich bei einer reinen Übersetzungs- oder Bildänderung nicht mehr – wie schon bisher bei Referenzänderungen. Die letzte Änderung des Objekts als Ganzes liefert modifiedRevision().
changeLog()
ChangeLogBuilder liest bei begrenzter Eintragszahl (z.B. changeLog(obj, 1)) die Historie rückwärts in Blöcken. Diese umfassten bei fehlenden Treffern immer nur zwei Revisionen; jetzt verdoppelt sich die Blockgröße (bis 1024 Revisionen), solange zu wenige Einträge gefunden werden.
Migration
AssociationStorageDescriptor hat die neue abstrakte Methode getBaseObjectColumn() (Name der Referenz, die das Basisobjekt einer Zeile hält). Eigene Implementierungen müssen sie implementieren. DefaultAssociationStorageDescriptor#baseObjectCol() heißt jetzt getBaseObjectColumn().
Wer sich darauf verlassen hat, dass eine Übersetzungsänderung das Änderungsdatum der Objektzeile bewegt, verwendet stattdessen modifiedRevision().