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 aber3.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"
| Feld | Erforderlich | Beschreibung |
|---|---|---|
ckModelId | Ja | Modell-ID mit Zielversion (z. B. MyModel-2.1.0) |
migrations | Ja | Array von Migrationsschritt-Referenzen |
migrations[].fromVersion | Ja | Quellversion, von der dieser Schritt migriert |
migrations[].toVersion | Ja | Zielversion, zu der dieser Schritt migriert |
migrations[].scriptPath | Ja | Relativer Pfad zur Migrationsskriptdatei |
migrations[].description | Nein | Menschenlesbare Beschreibung |
migrations[].breaking | Nein | Ob dieser Schritt breaking changes enthält (Standard: false) |
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.
| Typ | Beschreibung | Parameter |
|---|---|---|
EntityExists | Entitäten, die auf das Target passen, müssen existieren | target |
EntityNotExists | Es dürfen keine Entitäten existieren, die auf das Target passen | target |
CkModelVersionInstalled | Eine bestimmte CK-Modellversion muss installiert sein | ckModelId, version |
AttributeEquals | Ein Attribut muss einen bestimmten Wert haben | target, attribute, value |
Aktionen
Jeder Migrationsschritt führt eine dieser Aktionen aus:
| Aktion | Beschreibung |
|---|---|
Transform | Bestehende Entitäten transformieren (Typ ändern, Attribute umbenennen, Werte setzen) |
Update | Attributwerte auf bestehenden Entitäten aktualisieren |
Delete | Entitäten löschen, die auf das Target passen |
Add | Neue Entitäten hinzufügen |
Transform-Typen
Wird mit action: Transform verwendet:
| Typ | Beschreibung | Parameter |
|---|---|---|
ChangeCkType | Den CK-Typ passender Entitäten ändern | newCkTypeId |
SetValue | Einen statischen Wert auf einem Attribut setzen | targetAttribute, value |
RenameAttribute | Ein Attribut umbenennen | sourceAttribute, targetAttribute |
CopyAttribute | Einen Attributwert in ein neues Attribut kopieren | sourceAttribute, targetAttribute |
DeleteAttribute | Ein Attribut aus Entitäten entfernen | targetAttribute |
MapValue | Attributwerte über eine Lookup-Tabelle abbilden | targetAttribute, valueMapping |
Target-Spezifikation
Der target-Block wählt aus, auf welche Entitäten ein Schritt wirkt:
| Feld | Beschreibung |
|---|---|
ckTypeId | CK-Typ-ID als Ziel (z. B. MyModel/Widget) |
rtId | Bestimmte Runtime-Entitäts-ID |
rtWellKnownName | Well-known name der Entität |
filter | Filterausdruck für feingranulare Auswahl |
blueprintSourceOnly | Wenn 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:
| Verhalten | Beschreibung |
|---|---|
Fail | Den Schritt bei einem Konflikt stoppen (Standard) |
Skip | Die konfliktbehaftete Entität überspringen und fortfahren |
Overwrite | Mit neuen Werten überschreiben |
Nachvalidierungen
Validierungen werden ausgeführt, nachdem die Migrationsschritte abgeschlossen sind:
| Typ | Beschreibung | Parameter |
|---|---|---|
EntityExists | Prüfen, dass Entitäten eines Typs existieren | target |
NoEntitiesOfType | Prüfen, dass keine Entitäten des alten Typs verbleiben | target |
EntityCount | Prüfen, dass die Entitätsanzahl dem erwarteten Wert entspricht | target, 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:
- Durchsucht
ConstructionKit/migrations/nach*.yaml-Dateien - Bettet sie als Ressourcen mit dem Benennungsmuster
{RootNamespace}.migrations.{filename}.yamlein - Der
EmbeddedCkMigrationContentProviderlä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:
| Option | Standard | Beschreibung |
|---|---|---|
DryRun | false | Migration simulieren, ohne Änderungen vorzunehmen |
CreateBackup | false | Vor der Migration ein Tenant-Backup erstellen |
ContinueOnError | false | Mit dem nächsten Schritt fortfahren, wenn ein Schritt fehlschlägt |
Best Practices
- Versionieren Sie Ihre Migrationen sorgfältig — jeder Migrationsschritt sollte idempotent sein oder
preConditionsverwenden, um zu prüfen, ob er ausgeführt werden muss. - Verwenden Sie
continueOnError: truefü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: Warninghinzu, 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
fromVersionsollte höchstens einmal in der Kette vorkommen.