Zum Hauptinhalt springen

Migrationen von Construction-Kit-Modellen

Wenn sich ein Construction-Kit-(CK-)Modell zu einer neuen Version weiterentwickelt, müssen bestehende Runtime-Entitäten in den Tenant-Datenbanken möglicherweise aktualisiert werden, um dem neuen Schema zu entsprechen. CK-Modell-Migrationen automatisieren diesen Prozess, indem sie versionierte Transformationsskripte definieren, die Entitätsdaten während des Modellimports aktualisieren (Typen umbenennen, Attribute ändern usw.).

Überblick​

CK-Modell-Migrationen bestehen aus zwei Teilen:

  • Migrations-Metadaten (migration-meta.yaml) — deklarieren die verfügbaren Migrationsschritte und deren Versionskette
  • Migrationsskripte (*.yaml) — definieren die eigentlichen Datentransformationen für jeden Versionsschritt

Migrationsdateien werden im Ordner ConstructionKit/migrations/ eines CK-Modellprojekts abgelegt und beim Build automatisch als Assembly-Ressourcen eingebettet.

Wie die Auflösung des Migrationspfads funktioniert​

Wenn ein Tenant eine neue CK-Modellversion erhält, löst die Engine den Migrationspfad mit einer mehrschichtigen Strategie auf:

Automatisches Überbrücken von Versionslücken​

Die Engine überbrückt Versionslücken an beiden Enden der Migrationskette automatisch, ohne dass Entwickler leere Migrationseinträge erstellen müssen:

  • Start-Lücke: Wenn sich der Tenant auf einer älteren Version (z. B. 2.2.0) als der früheste Einstiegspunkt der Migration (z. B. 3.0.1) befindet, erstellt die Engine einen No-op-Brückenschritt. Es ist keine Datenmigration erforderlich, da die Daten des Tenants mit dem Beginn der Kette kompatibel sind.
  • End-Lücke: Wenn die Migrationskette die exakte Zielversion nicht erreicht (z. B. endet die Kette bei 3.1.1, das neue Modell ist aber 3.1.2), führt die Engine alle verfügbaren Migrationen aus und behandelt den verbleibenden Versions-Bump als reine Schemaänderung.

Beispiel: Ein Tenant auf Version 2.2.0, der die Modellversion 3.1.2 mit ab 3.0.1 definierten Migrationen erhält:

2.2.0 → 3.0.1 (auto-bridge, no-op)
3.0.1 → 3.0.2 (migration script executed)
3.0.2 → 3.0.3 (migration script executed)
3.0.3 → 3.1.0 (migration script executed)
3.1.0 → 3.1.1 (migration script executed)
3.1.1 → 3.1.2 (auto-bridge, schema-only)

Migrationen erstellen​

Dateistruktur​

Legen Sie Migrationsdateien im Verzeichnis ConstructionKit/migrations/ Ihres CK-Modellprojekts ab:

MyModel/
└── ConstructionKit/
├── ckModel.yaml
├── types/
├── attributes/
└── migrations/
├── migration-meta.yaml
├── 1.0.0-to-2.0.0.yaml
└── 2.0.0-to-2.1.0.yaml

Migrations-Metadaten​

Die Datei migration-meta.yaml deklariert die verfügbare Migrationskette:

$schema: https://schemas.meshmakers.cloud/ck-migration-meta.schema.json
ckModelId: MyModel-2.1.0
migrations:
- fromVersion: "1.0.0"
toVersion: "2.0.0"
scriptPath: 1.0.0-to-2.0.0.yaml
description: "Rename Widget type to Component"
breaking: true
- fromVersion: "2.0.0"
toVersion: "2.1.0"
scriptPath: 2.0.0-to-2.1.0.yaml
description: "Add default status attribute to all Components"
FeldErforderlichBeschreibung
ckModelIdJaModell-ID mit Zielversion (z. B. MyModel-2.1.0)
migrationsJaArray von Migrationsschritt-Referenzen
migrations[].fromVersionJaQuellversion, von der dieser Schritt migriert
migrations[].toVersionJaZielversion, zu der dieser Schritt migriert
migrations[].scriptPathJaRelativer Pfad zur Migrationsskriptdatei
migrations[].descriptionNeinMenschenlesbare Beschreibung
migrations[].breakingNeinOb dieser Schritt breaking changes enthält (Standard: false)
info

Sie müssen nur Migrationseinträge für Schritte definieren, die Datentransformationen erfordern. Die Engine überbrückt automatisch alle Versionslücken, bei denen keine Datenmigration nötig ist.

Migrationsskripte​

Jedes Migrationsskript definiert Vorbedingungen, Transformationsschritte und Nachvalidierungen:

$schema: https://schemas.meshmakers.cloud/ck-migration.schema.json
sourceVersion: "1.0.0"
targetVersion: "2.0.0"
description: |
Renames the Widget CK type to Component.

preConditions:
- type: EntityExists
target:
ckTypeId: MyModel/Widget

steps:
- stepId: rename-widget-to-component
description: "Change CkTypeId from Widget to Component"
action: Transform
target:
ckTypeId: MyModel/Widget
transform:
type: ChangeCkType
newCkTypeId: MyModel/Component
onConflict: Skip
continueOnError: false

postValidations:
- validationId: no-widgets-remain
description: "Ensure no entities with legacy Widget type exist"
type: NoEntitiesOfType
target:
ckTypeId: MyModel/Widget
severity: Warning

Referenz für Migrationsskripte​

Vorbedingungen​

Bedingungen, die erfüllt sein müssen, bevor die Migration ausgeführt wird. Wenn eine Vorbedingung nicht erfüllt ist, wird der Migrationsschritt übersprungen.

TypBeschreibungParameter
EntityExistsEntitäten, die auf das Target passen, müssen existierentarget
EntityNotExistsEs dürfen keine Entitäten existieren, die auf das Target passentarget
CkModelVersionInstalledEine bestimmte CK-Modellversion muss installiert seinckModelId, version
AttributeEqualsEin Attribut muss einen bestimmten Wert habentarget, attribute, value

Aktionen​

Jeder Migrationsschritt führt eine dieser Aktionen aus:

AktionBeschreibung
TransformBestehende Entitäten transformieren (Typ ändern, Attribute umbenennen, Werte setzen)
UpdateAttributwerte auf bestehenden Entitäten aktualisieren
DeleteEntitäten löschen, die auf das Target passen
AddNeue Entitäten hinzufügen

Transform-Typen​

Wird mit action: Transform verwendet:

TypBeschreibungParameter
ChangeCkTypeDen CK-Typ passender Entitäten ändernnewCkTypeId
SetValueEinen statischen Wert auf einem Attribut setzentargetAttribute, value
RenameAttributeEin Attribut umbenennensourceAttribute, targetAttribute
CopyAttributeEinen Attributwert in ein neues Attribut kopierensourceAttribute, targetAttribute
DeleteAttributeEin Attribut aus Entitäten entfernentargetAttribute
MapValueAttributwerte über eine Lookup-Tabelle abbildentargetAttribute, valueMapping

Target-Spezifikation​

Der target-Block wählt aus, auf welche Entitäten ein Schritt wirkt:

FeldBeschreibung
ckTypeIdCK-Typ-ID als Ziel (z. B. MyModel/Widget)
rtIdBestimmte Runtime-Entitäts-ID
rtWellKnownNameWell-known name der Entität
filterFilterausdruck für feingranulare Auswahl
blueprintSourceOnlyWenn true, nur durch Blueprints erstellte Entitäten als Ziel (Standard: false)

Filterausdrücke​

Filter ermöglichen eine feingranulare Auswahl von Entitäten innerhalb eines Targets:

filter:
attribute: Status
operator: Eq
value: "active"

Unterstützte Operatoren: Eq, Ne, Exists, NotExists, Contains, StartsWith

Filter können mit boolescher Logik kombiniert werden:

filter:
and:
- attribute: Status
operator: Eq
value: "active"
- attribute: Type
operator: Ne
value: "deprecated"

Konfliktverhalten​

Steuert, was passiert, wenn ein Migrationsschritt auf einen Konflikt stößt:

VerhaltenBeschreibung
FailDen Schritt bei einem Konflikt stoppen (Standard)
SkipDie konfliktbehaftete Entität überspringen und fortfahren
OverwriteMit neuen Werten überschreiben

Nachvalidierungen​

Validierungen werden ausgeführt, nachdem die Migrationsschritte abgeschlossen sind:

TypBeschreibungParameter
EntityExistsPrüfen, dass Entitäten eines Typs existierentarget
NoEntitiesOfTypePrüfen, dass keine Entitäten des alten Typs verbleibentarget
EntityCountPrüfen, dass die Entitätsanzahl dem erwarteten Wert entsprichttarget, expectedCount

Jede Validierung hat eine severity (Error oder Warning). Warnungen werden protokolliert, führen aber nicht zum Fehlschlagen der Migration.

Vollständiges Beispiel​

Dieses Beispiel zeigt eine Migration, die einen CK-Typ umbenennt und zwei Subtypen zu einem einzigen Typ zusammenführt:

migration-meta.yaml:

$schema: https://schemas.meshmakers.cloud/ck-migration-meta.schema.json
ckModelId: System.Communication-3.1.1
migrations:
- fromVersion: "3.0.1"
toVersion: "3.0.2"
scriptPath: 3.0.1-to-3.0.2.yaml
description: "Rename DataPipeline to DataFlow"
breaking: true
- fromVersion: "3.0.2"
toVersion: "3.0.3"
scriptPath: 3.0.2-to-3.0.3.yaml
description: "Retry rename for tenants where previous migration failed"
breaking: true
- fromVersion: "3.0.3"
toVersion: "3.1.0"
scriptPath: 3.0.3-to-3.1.0.yaml
description: "Merge EdgeAdapter/MeshAdapter into Adapter"
breaking: true
- fromVersion: "3.1.0"
toVersion: "3.1.1"
scriptPath: 3.1.0-to-3.1.1.yaml
description: "Retry merge after engine fix"
breaking: true

3.0.3-to-3.1.0.yaml (Vereinheitlichung der Typhierarchie):

$schema: https://schemas.meshmakers.cloud/ck-migration.schema.json
sourceVersion: "3.0.3"
targetVersion: "3.1.0"
description: |
Merges EdgeAdapter/MeshAdapter into Adapter and
EdgePipeline/MeshPipeline into Pipeline.

steps:
- stepId: migrate-edge-adapter
description: "Migrate EdgeAdapter to Adapter"
action: Transform
target:
ckTypeId: System.Communication/EdgeAdapter
blueprintSourceOnly: false
transform:
type: ChangeCkType
newCkTypeId: System.Communication/Adapter
onConflict: Skip
continueOnError: true

- stepId: migrate-mesh-adapter
description: "Migrate MeshAdapter to Adapter"
action: Transform
target:
ckTypeId: System.Communication/MeshAdapter
blueprintSourceOnly: false
transform:
type: ChangeCkType
newCkTypeId: System.Communication/Adapter
onConflict: Skip
continueOnError: true

- stepId: migrate-edge-pipeline
description: "Migrate EdgePipeline to Pipeline"
action: Transform
target:
ckTypeId: System.Communication/EdgePipeline
blueprintSourceOnly: false
transform:
type: ChangeCkType
newCkTypeId: System.Communication/Pipeline
onConflict: Skip
continueOnError: true

Build-Integration​

Migrationsdateien werden während des Builds automatisch als Assembly-Ressourcen eingebettet. Dies wird durch die MSBuild-Eigenschaft OctoEmbedCkMigrations gesteuert (Standard: true).

Das Build-System:

  1. Durchsucht ConstructionKit/migrations/ nach *.yaml-Dateien
  2. Bettet sie als Ressourcen mit dem Benennungsmuster {RootNamespace}.migrations.{filename}.yaml ein
  3. Der EmbeddedCkMigrationContentProvider lädt sie zur Laufzeit

Um das Einbetten zu deaktivieren (z. B. für dateisystembasierte Migrationen):

<PropertyGroup>
<OctoEmbedCkMigrations>false</OctoEmbedCkMigrations>
</PropertyGroup>

Migrationsoptionen​

Wenn Migrationen programmgesteuert ausgeführt werden, stehen diese Optionen zur Verfügung:

OptionStandardBeschreibung
DryRunfalseMigration simulieren, ohne Änderungen vorzunehmen
CreateBackupfalseVor der Migration ein Tenant-Backup erstellen
ContinueOnErrorfalseMit dem nächsten Schritt fortfahren, wenn ein Schritt fehlschlägt

Best Practices​

  • Versionieren Sie Ihre Migrationen sorgfältig — jeder Migrationsschritt sollte idempotent sein oder preConditions verwenden, um zu prüfen, ob er ausgeführt werden muss.
  • Verwenden Sie continueOnError: true für Schritte, die möglicherweise nur teilweise greifen (z. B. das Zusammenführen mehrerer Subtypen, von denen einige nicht in jedem Tenant existieren).
  • Fügen Sie Nachvalidierungen mit severity: Warning hinzu, um Migrationsergebnisse zu prüfen, ohne den Prozess zu blockieren.
  • Testen Sie Migrationen lokal, bevor Sie sie auf Produktions-Tenants ausrollen. Verwenden Sie DryRun: true, um zu validieren, ohne Daten zu ändern.
  • Keine leeren Migrationseinträge nötig — die Engine überbrückt Versionslücken automatisch. Erstellen Sie Migrationsskripte nur für Schritte, die tatsächlich Daten transformieren.
  • Halten Sie Migrationsketten linear — vermeiden Sie verzweigte Migrationspfade. Jede fromVersion sollte höchstens einmal in der Kette vorkommen.