Work in Progress
Diese Seite ist aktuell im Review! Die Seite wurde noch nicht qualitätsgesichert und kann Fehler enthalten.
Die verlinkten Seiten sind ggf. nur für Schleupen-Mitarbeiter sichtbar.

Chronologische Daten

Bestimmte Attribute erfordern eine zeitabhängige Speicherung von Werten. Beispiel: Preis eines Buchs. Dieser Preis hat zu unterschiedlichen Zeitpunkten unterschiedliche Werte. In der Geschäftslogik sollen neben dem aktuellen Wert auch die Werte der Vergangenheit bzw. Zukunft bekannt sein. Diese können ggf. für die Verarbeitung nötig sein.

Aus dem Attribut Preis eines Objektes wird also im Prinzip ein zeitabhängiges Attribute Preis(t) . Dies ist (natürlich) in C# so nicht umsetzbar. Hilfsweise wird die hier vorgestellte Bibliothek eingesetzt.

Desing

Grundvarianten

Folgende Varianten stehen im Framework zur Verfügung (Namensraum Schleupen.CS.PI.Framework.Chronology.Collections):

  • TimeBoxedValueCollection
    • Lücken erlaubt
    • mehrere Werte zur gleichen Zeit erlaubt
  • TimeBoxedValueSet
    • Lücken erlaubt
    • nur max. ein Wert zur gleichen Zeit erlaubt
  • TimedValueRay
    • keine Lücken erlaubt
    • nur max. ein Wert zur gleichen Zeit erlaubt
Operationen auf Zeitscheiben

Alle Operationen auf diese Werten laufen nach folgendem Verfahren ab:

  • Split
  • Act
  • Melt

Die folgenden Beispiele zeigen, wie man mehrere Attribute, die den Zustand des umhüllenden Objekts ausmachen, arbeitet. Somit können für das umhüllende Objekt die unterschiedlichen Zustände zu den unterschiedlichen Zeitpunkten verwendet werden.

Aufgabe:

  1. Split
    Trenne alle Intervalle an den Zeitpunkten auf, an denen mindestens eine Intervallgrenze existiert:
  2. Act
    Auf diesen Intervallen konstanter Attribute können jegliche Operationen zeitunabhängig durchgeführt werden:
  3. Melt
    Verschmelze solche Nachbar-Intervalle, in denen alle Attribute gleich sind, zu einem Intervall:
Automatische Optimierung

Benachbarte zeitlich begrenzte Werte werden in allen Collections beim Einfügen automatisch zusammengefasst. Ist der eigentliche Wert gleich, so werden benachbarte Intervalle also zu einem den Gesamtraum umfassenden Intervall verschmolzen.

Intervalltyp

Der Intervalltyp gibt an, ob geschlosse oder rechts-offene Intervalle verwendet werden. Bei einen Geschäftsjahr ist es z.B. sinnvoll geschlossene Intervalle zu verwenden, damit in der UI und der Datenbank z.B. 2014-01-01 bis 2014-12-31 zu sehen ist anstelle von 2014-01-01 bis 2015-01-01. Die zweite Darstellung könnte durch den Anwender als schwer verständlich empfunden werden. Welcher Intervalltyp zu verwenden ist, hängt vom jeweiligen Kontext ab und ist eine fachliche Entscheidung.

Die Intervalle sind dabei aus Konsistenzgründen auf allen Ebenen gleich, das UI sollte also dieselben Intervalle anzeigen wie diese in der Datenbank abgelegt werden.

Intervallerzeugung
  • Es können Intervalle von einem Datum bis zu einem anderen Datum erzeugt werden.
DateTimeOffset from = new DateTimeOffset(2016, 1, 1, 0, 0, 0, new TimeSpan(0, 0, 0));
DateTimeOffset to = new DateTimeOffset(2016, 12, 31, 0, 0, 0, new TimeSpan(0, 0, 0));
TimeBox timeBox = new TimeBox(from, to);
  • Es können Intervalle rechts oder links unbeschränkte Intervalle erzeugt werden.
DateTimeOffset from = new DateTimeOffset(2016, 1, 1, 0, 0, 0, new TimeSpan(0, 0, 0));
TimeBox rightUnboundTimeBox = TimeBox.CreateRightUnbound(from);
 
DateTime to = new DateTimeOffset(2016, 12, 31, 0, 0, 0, new TimeSpan(0, 0, 0));
TimeBox leftUnboundTimeBox = TimeBox.CreateLeftUnbound(to);
Genauigkeit

Die Genauigkeit gibt an, welche Zeitpunkte als identisch betrachtet werden. Bei einer Genauigkeit Tag bezeichnen somit die Werte 2014-07-17 00:00:00 und 2014-07-17 12:15:00 denselben Zeitpunkt. Folgende Genauigkeiten stehen zur Verfügung:

  • Year
  • Day
  • Month
  • Hour
  • Minute
  • Second
  • None (anwendendes Land muss Genauigkeit sicherstellen, es wird auf maximale Genauigkeit verglichen)

Bei geschlossenen Intervallen enden angrenzende Intervalle automatisch immer an einem durch die Granularität definierten vorigen Zeitpunkt.

Rundung

Alle Zeitpunkte werden durch die Framework Klassen (außer bei Granularität None) automatisch gerundet, so dass diese in Datenbank und Domäne immer konsistent sind.

KDM/KSM

Im KDM stehen zur weiteren Verwendung in den KSM Diensten spezialisierte Datentypen bereit, die damit ausdrücken können, ob ein Service die Daten als offenes oder geschlossenes Intervall liefert/erwartet.

Die folgenden Beispiele zeigen das Verhalten der verschiedenen Collection-Typen bei hinzufügen neuer Werte.

TimeBoxedValueCollection

Hier wird der Wert 2 hinzugefügt. Eine Optimierung ist hier nicht nötig, da alle Werte unterschiedlich sind und mehrere Werte je Zeitraum existieren können.

  [---1---[    [---3---[
+      [---2---[

=>[---1---[    [---3---[
       [---2---[
TimeBoxedValueSet

Durch das Hinzufügen des Wertes 3 werden Teile der existierenden Werte überschrieben.

  [---1---[    [---2----[
+      [----3----[
  
=>[-1-[[----3----[[--2--[

Durch das Hinzufügen des zweiten Wertes 1 findet eine Optimierung statt.

  [---1---[    [---2---[
+     [---1---[
  
=>[-----1-----[[---2---[
TimedValueRay

Hier wird der Wert 4 mit Add hinzugefügt. Dieser überschreibt die existierenden Werte im selben Zeitraum.

  [---1---[[----2----[[---3---
+                [----4-----

=>[---1---[[-2--[[---4------  

Hier wird der Wert 4 mit Insert hinzugefügt. Dieser fügt den Wert zwischen die existierenden Werte hinzu - Endzeitpunkt wird von der Startzeitpunkt des nächsten zeitlich begrenzten Werts übernommen.

  [---1---[[----2----[[---3---
+                [----4-----

=>[---1---[[-2--[[-4-[[---3---
-----  

Weitere Beispiele sind in den Unittests der Assembly Core.Tests im Namensraum Chronology zu finden.

Chronologische Beziehungen zwischen Aggregaten

Analog zu den Collections zum Arbeiten mit chronologisierten Value Types können auch Beziehungen zwischen Aggregaten chronologisiert werden. Hierzu werden die Collections TimeBoxedAssociationCollection, TimeBoxedAssociationSet und TimedAssociationRay mit gleicher Semantik genutzt.

Diese Art der Chronologisierung ist nur beim Aggregate Boundary Muster von Bedeutung. Falls die Aggregate per Id verknüpft sind, kann die Id einfach als Value Type chronologisiert werden.

Falls bei der Arbeit mit einer chronologischen Aggregatbeziehung neue Einträge entstehen (z.B. ein bestehender Zeitstreifen wird zerteilt), wird im Gegensatz zu Value Types bei der Chronologisierung von Aggregatbeziehungen keine Kopie von bestehenden Entitäten erzeugt, sondern eine Referenz auf das gleiche Aggregate Boundary.

Chronologische Eltern-Kind Beziehungen

Analog zu den Collections zum Arbeiten mit chronologisierten Value Types können auch Eltern-Kind Beziehungen innerhalb von Aggregaten chronologisiert werden. Hierzu werden die Collections TimeBoxedChildEntityCollection, TimeBoxedChildEntitySet und TimedChildEntityRay mit gleicher Semantik genutzt.

Falls bei der Arbeit mit einer chronologischen Eltern-Kindbeziehung neue Einträge entstehen (z.B. ein bestehender Zeitstreifen wird zerteilt), wird wie bei Values Types eine Kopie des Kindelementes erzeugt, die Verweise zeigen also auf unterschiedliche Objekte mit gleichen Daten. Kind-Elemente implementieren hierfür das Interface IClonableEntity.

Es ist fachlich zu entscheiden, ob in der Clone() Methode eine tiefe oder flache Kopie des zu Objektes erstellt wird.

Migration TimedValueRay to TimeChildEntityRay

Um TimedValueRay in TimeChildEntityRay zu migrieren sind die folgenden Schritte notwendig:

  • Ableitung von TimedValue auf Ableitung von TimedChildEntity ändern
  • TEntity von struct auf class ändern und IAggregateChild implementieren
  • TEntity muss zusätzlich IClonableEntity, IEquatable implementieren
  • Der Konstruktor von TEntity muss eine ParentId entgegen nehmen
Setzen von ParentId auf TimedValueRay

Um die ParentId auf einem TimedValueRay zu setzen, darf der Value kein primitiver Datentyp sein. Man kann allerdings selbst einen struct definieren, der die ParentId entgegen nimmt.

Ab PI 3.19 kann hier ein Fabrikmethode zur Erzeugung des Objekts angegeben werden, sodass man hier einfach eingreifen kann. Hierüber kann auch die Id gesetzt werden!

Abgrenzung

Dies ist nicht mit einer Historie der Werte zu verwechseln! Bei chronologischen Daten werden die Werte zu mehreren Zeitpunkten gleichzeitig für die Verarbeitung benötigt. Diese Bibliothek ist kein Ersatz für ein Änderungsprotokoll.

Cookie Consent mit Real Cookie Banner