CodamAIDocs
Themafertig

Beziehungstypen und Recursive-Flags

Die vier Beziehungstypen und die Erlaubnisse CREATE, UPDATE und DELETE, die festlegen, was CDMS über eine Beziehung hinweg tun darf.

Ausprägungen
ONETOONEONETOMANYMANYTOONEMANYTOMANYFlag CREATEFlag UPDATEFlag DELETELesen: Rolle statt FlagRollen für Kinder

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:

  1. den Beziehungstyp: Wie viele Objekte stehen auf jeder Seite?
  2. 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
TypHubbedeutetGegenseiteim JSON
ONETOONE1:1genau ein Objekt auf jeder SeiteONETOONEein Objekt: "mainPhone": { "id": … }
ONETOMANY1:ndieses Objekt hat vieleMANYTOONEeine Liste: "employees": [ … ]
MANYTOONEn:1viele davon gehören zu einemONETOMANYein Objekt: "company": { "id": … }
MANYTOMANYn:mviele auf beiden SeitenMANYTOMANYeine 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

Was die Flags erlauben
CREATEUPDATEDELETE
gilt fürein Kind ohne id im Requestein Kind mit id und weiteren Feldernein Kind, das aus der Beziehung fällt, und alle Kinder, wenn das Elternobjekt gelöscht wird
ohne das Flag400 recursive-create-not-allowed|<feld>das Kind wird nur verknüpft, seine Felder bleiben unberührtdas Kind wird nur entkoppelt und bleibt bestehen
Rolle, die geprüft wirdAnlegerolle des KindmodellsÄnderungsrolle des KindmodellsLöschrolle des Kindmodells
Die Flags im Einsatz

Wann: Du legst eine Firma mit einem neuen Mitarbeiter an.

  1. 1
    Client→CDMS
    schickt "employees": [{ "firstname": "Anna", "lastname": "Schmidt" }], also ein Kind ohne id
  2. 2
    CDMS
    Flag CREATE an employees?
  3. 3
    CDMS→Client
    nein → 400 recursive-create-not-allowed|employees
  4. 4
    CDMS→Database
    ja → 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.

  1. 1
    Client→CDMS
    schickt "employees": [{ "id": "k1…", "firstname": "Anna", "lastname": "Meyer" }]
  2. 2
    CDMS
    Flag UPDATE an employees?
  3. 3
    CDMS
    nein → verknüpft k1… nur, lastname bleibt, wie es war
  4. 4
    CDMS→Database
    ja → ä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.

  1. 1
    Client→CDMS
    schickt die Liste employees ohne Ben, oder DELETE /company/delete/{id}
  2. 2
    CDMS
    Flag DELETE an employees?
  3. 3
    CDMS→Database
    nein → Ben bleibt bestehen, sein Feld company wird leer
  4. 4
    CDMS→Database
    ja → 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).

Darf das Kind geschrieben werden?
Aktion am KindRolle des KindmodellsFeldrolle am BeziehungsfeldErgebnis
nur verknüpfen (POST, PUT) oder entkoppeln––erlaubt, keine Rolle des Kindes nötig
anlegen, ändern, löschenja–erlaubt
anlegen, ändern, löschenneinjaerlaubt, nur auf diesem Weg
anlegen, ändern, löschenneinnein403 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 BeziehungKind bei POST /createKind bei PUT /update
keinsnur id und @typenur id und @type
CREATEalle Felder des Kindesnur id und @type
UPDATEnur id und @typealle Felder des Kindes
CREATE und UPDATEalle Felderalle 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

Quellen im Code und in der Wissensdatenbank
  • CDMS/cdms-generator – CdmsYamlLoader (relationship, reference, recursive, normalizeRelType, applyRecursionType), EntityProcessor (JPA-Annotationen, cascade, JoinTable), RestPayloadProcessor (CreatePayload/UpdatePayload vs. IdWrapperPayload)
  • CDMS/cdms-system-layer – AbstractLayer (setModel, recursiveCreate/Update/Patch, detachOrDeleteMember, recursiveDelete, enterField)
  • commons – MetaFieldInfo (isRecursiveCreate/Update/Delete)
  • CDMS/frontend – app/components/cdms/FieldDialog.vue (Tab Rekursion)
  • hub-backend – ModelDesignService (Gegenfeld)
  • CDMS/cdms-integrationtest – structure/models.yaml (Company, Employee, Person, Group), AbstractRecursiveTest, AbstractRecursivePatch, AbstractUpdateTest, AbstractRoleDenialTest, AbstractFieldRoleTest
Suchen