Worum es geht
Eine Beziehung verbindet zwei Modelle: Ein Mitarbeiter gehört zu einer Firma, eine Firma hat viele Mitarbeiter. In CDMS ist eine Beziehung immer ein Feldpaar: je ein Feld auf beiden Seiten, die aufeinander zeigen. Im Hub legst du eine Seite an, die Gegenseite entsteht automatisch.
An jeder Seite legst du zwei Dinge fest:
- den Beziehungstyp: Wie viele Objekte stehen auf jeder Seite?
- die Recursive-Flags: Was darf CDMS über diese Beziehung hinweg mit den verbundenen Objekten tun?
Die vier Beziehungstypen
flowchart LR
subgraph one ["1:1 ONETOONE"]
P[Person] --- T[Haupttelefon]
end
subgraph many ["1:n ONETOMANY / n:1 MANYTOONE"]
C[Firma] -->|employees| E1[Mitarbeiter]
C --> E2[Mitarbeiter]
E1 -.->|company| C
end
subgraph mm ["n:m MANYTOMANY"]
G1[Gruppe A] --- R1[Rolle 1]
G1 --- R2[Rolle 2]
G2[Gruppe B] --- R2
end
| Typ | Hub | bedeutet | Gegenseite | im JSON |
|---|---|---|---|---|
ONETOONE | 1:1 | genau ein Objekt auf jeder Seite | ONETOONE | ein Objekt: "mainPhone": { "id": … } |
ONETOMANY | 1:n | dieses Objekt hat viele | MANYTOONE | eine Liste: "employees": [ … ] |
MANYTOONE | n:1 | viele davon gehören zu einem | ONETOMANY | ein Objekt: "company": { "id": … } |
MANYTOMANY | n:m | viele auf beiden Seiten | MANYTOMANY | eine Liste: "roles": [ … ] |
In der Datenbank liegt bei 1:n und n:1 ein Fremdschlüssel in der Tabelle der n-Seite, bei 1:1 in einer der beiden Tabellen, bei n:m in einer eigenen Verbindungstabelle. Welche Tabelle das ist, entscheidet der Generator. Für den Client spielt es keine Rolle: Er schreibt und liest die Beziehung von beiden Seiten gleich. Siehe Beide Seiten einer Beziehung und Many-to-Many über eine Verbindungstabelle.
So sieht das im Modell aus
# Company – the "one" side
- name: "employees"
relationship: "ONETOMANY"
reference:
id: "m-employee" # target model
name: "company" # field on the other side
recursive:
create: true
update: true
delete: true
# Employee – the "many" side
- name: "company"
relationship: "MANYTOONE"
reference:
id: "m-company"
name: "employees"
Die Flags hängen an einer Seite. Hier darf die Firma ihre Mitarbeiter anlegen, ändern und löschen. Umgekehrt darf ein Mitarbeiter seine Firma nur verknüpfen, weil company keine Flags hat. Im Hub setzt du die Flags im Reiter Rekursion des Beziehungsfeldes. Ohne Angabe sind alle drei aus.
Die drei Flags
| CREATE | UPDATE | DELETE | |
|---|---|---|---|
| gilt für | ein Kind ohne id im Request | ein Kind mit id und weiteren Feldern | ein Kind, das aus der Beziehung fällt, und alle Kinder, wenn das Elternobjekt gelöscht wird |
| ohne das Flag | 400 recursive-create-not-allowed|<feld> | das Kind wird nur verknüpft, seine Felder bleiben unberührt | das Kind wird nur entkoppelt und bleibt bestehen |
| Rolle, die geprüft wird | Anlegerolle des Kindmodells | Änderungsrolle des Kindmodells | Löschrolle des Kindmodells |
Wann: Du legst eine Firma mit einem neuen Mitarbeiter an.
-
1Client→CDMSschickt
"employees": [{ "firstname": "Anna", "lastname": "Schmidt" }], also ein Kind ohneid -
2CDMSFlag CREATE an
employees? -
3CDMS→Clientnein → 400
recursive-create-not-allowed|employees -
4CDMS→Databaseja → legt den Mitarbeiter an und verbindet ihn mit der Firma
Ergebnis: Der Mitarbeiter bekommt eine eigene id, eigene Defaultwerte und eigenes _createdOn.
Wann: Du änderst über die Firma den Namen eines bestehenden Mitarbeiters.
-
1Client→CDMSschickt
"employees": [{ "id": "k1…", "firstname": "Anna", "lastname": "Meyer" }] -
2CDMSFlag UPDATE an
employees? -
3CDMSnein → verknüpft
k1…nur,lastnamebleibt, wie es war -
4CDMS→Databaseja → ändert den Mitarbeiter mit, nach den Regeln des Verbs (PUT ersetzt, PATCH ändert)
Ergebnis: Siehe Die vier Fälle beim verschachtelten Schreiben.
Wann: Ein Mitarbeiter fällt aus der Liste, oder die Firma wird gelöscht.
-
1Client→CDMSschickt die Liste
employeesohne Ben, oderDELETE /company/delete/{id} -
2CDMSFlag DELETE an
employees? -
3CDMS→Databasenein → Ben bleibt bestehen, sein Feld
companywird leer -
4CDMS→Databaseja → Ben wird gelöscht, mit seinen DELETE-Hooks und seinen eigenen abhängigen Kindern
Ergebnis: Ein Kind mit DELETE-Flag heißt abhängiges Kind: Es lebt nur mit seinem Elternobjekt. Siehe Listen als Zielzustand und Abhängige Objekte (Kaskaden).
Und das Lesen?
Fürs Lesen gibt es kein Flag. Ob du eine Beziehung lesen darfst, entscheidet die Leserolle des Zielmodells, oder eine Feldrolle am Beziehungsfeld. Welche verbundenen Objekte in der Antwort stehen, bestimmt deine response. Siehe Referenzen und Listen ausbauen.
Welche Rollen für ein Kind gelten
Jedes Kind, das CDMS über eine Beziehung anlegt, ändert oder löscht, wird mit den Rollen seines eigenen Modells geprüft. Wer über die Firma Mitarbeiter anlegt, braucht also auch das Recht, Mitarbeiter anzulegen.
Statt der Rolle des Kindmodells reicht auch eine Feldrolle am Beziehungsfeld, etwa company-employees-create. Sie erlaubt die Aktion nur auf diesem Weg, über die Firma. Siehe Rechte auf Beziehungen (Feldrollen).
| Aktion am Kind | Rolle des Kindmodells | Feldrolle am Beziehungsfeld | Ergebnis |
|---|---|---|---|
| nur verknüpfen (POST, PUT) oder entkoppeln | – | – | erlaubt, keine Rolle des Kindes nötig |
| anlegen, ändern, löschen | ja | – | erlaubt |
| anlegen, ändern, löschen | nein | ja | erlaubt, nur auf diesem Weg |
| anlegen, ändern, löschen | nein | nein | 403 missing-permission|<rolle>, die ganze Anfrage scheitert |
Was die Flags am Payload ändern
Die Flags bestimmen auch, welche Felder der Client für ein Kind überhaupt schicken kann. Der Generator erzeugt die Payload-Klassen danach:
| Flag an der Beziehung | Kind bei POST /create | Kind bei PUT /update |
|---|---|---|
| keins | nur id und @type | nur id und @type |
| CREATE | alle Felder des Kindes | nur id und @type |
| UPDATE | nur id und @type | alle Felder des Kindes |
| CREATE und UPDATE | alle Felder | alle Felder |
Schickst du bei einer Beziehung ohne passendes Flag weitere Felder mit, fallen sie beim Einlesen weg. PATCH liest data ohne feste Klasse ein, dort gelten die Regeln unter Die vier Fälle. Die OpenAPI-Beschreibung zeigt dir also genau, was an welcher Beziehung möglich ist.
Fallen
Wie es weitergeht
- Was bei id und Flag genau passiert: Die vier Fälle beim verschachtelten Schreiben
- Listen im Payload: Listen als Zielzustand
- Beziehungen im Hub anlegen: Modellieren im Hub