CodamAIDocs
Themafertig

Der Ablauf eines DELETE

Sichtbarkeit prüfen, laden, Rollen prüfen, Kaskade, Hooks, entfernen: die Schritte eines Löschvorgangs und die Fehler an jeder Stelle. Es gibt nur hartes Löschen.

Ausprägungen
normales ModellSingletonabstraktes Modellunsichtbar → 404ohne Löschrolle → 403zweimal löschen

Worum es geht

Ein Objekt löschst du mit einer einzigen Anfrage:

Anfrage
DELETE /api/rest/company/delete/c4…
Antwort
200, leerer Körper

Die Anfrage hat keinen Körper, und die Antwort hat auch keinen. Es gibt kein response, weil es nach dem Löschen nichts mehr zu lesen gibt.

CDMS löscht hart: Die Zeile verschwindet aus der Datenbank. Es gibt kein Feld „gelöscht“ und keinen Papierkorb. Was danach noch übrig ist, steht unter Was nach dem Löschen bleibt.

Die Stationen

DELETE /company/delete/{id}
  1. CDMS
    Sichtbarkeit
    Gibt es die Zeile, und darfst du sie sehen? Gleiche Filter wie beim Lesen: Mandant, eigene Daten, Attributfilter.
    ↳ nein 404 not-found|<Dto>|<id>
  2. CDMS
    Löschrolle
    Hast du die Löschrolle des Modells, hier company-delete?
    ↳ nein 403 missing-permission|company-delete
  3. CDMS
    Kaskade
    Abhängige Kinder mitlöschen, alle anderen Beziehungen lösen. Jedes gelöschte Kind braucht die Löschrolle seines Modells.
    ↳ nein 403 missing-permission|<rolle des kindes>
  4. Hook
    Hooks
    Before-Hooks aller betroffenen Objekte. Ein Hook kann das Löschen mit einem Fehler verhindern.
    ↳ nein Fehler des Hooks
  5. Database
    Datenbank
    Lassen sich alle Zeilen entfernen und alle gelösten Beziehungen speichern?
    ↳ nein 400 constraint-violation, z. B. ein gelöstes Kind darf ohne Elternobjekt nicht existieren
  6. 200 ohne Körper, die Transaktion ist committet

Scheitert eine Station, rollt CDMS die ganze Transaktion zurück. Das Objekt, seine Kinder und alle gelösten Verbindungen bleiben, wie sie waren.

Der Ablauf im Einzelnen

sequenceDiagram
    participant C as Client
    participant D as CDMS
    participant H as Hook
    participant DB as Datenbank
    C->>D: DELETE /company/delete/c4…
    D->>DB: zählt die Zeile mit den Filtern des Lesens
    DB-->>D: 1 (sonst 404)
    D->>DB: lädt das vollständige Objekt
    D->>D: Löschrolle der Firma prüfen
    D->>D: Kaskade: Kinder prüfen und vormerken, Beziehungen lösen
    D->>H: Before-Hooks (Firma und jedes Kind)
    D->>DB: entfernen
    D->>H: After-Hooks (Firma und jedes Kind)
    D->>DB: flush, dann commit
    D-->>C: 200, leerer Körper

Drei Dinge fallen auf:

  1. Sichtbarkeit kommt vor der Rolle. Ist die Zeile für dich unsichtbar, bekommst du 404, auch wenn dir die Löschrolle fehlt. So verrät CDMS nicht, ob es eine fremde id gibt. Siehe Warum Unsichtbares 404 liefert.
  2. Eine Leserolle brauchst du nicht. Die Sichtbarkeitsprüfung nutzt die Filter des Lesens, aber nicht die Leserolle. order-delete allein genügt, um eine sichtbare Bestellung zu löschen.
  3. Nichts wird zurückgelesen. Anders als bei Create, PUT und PATCH gibt es nach dem Löschen kein Zurücklesen und keinen READ-Hook.

Hooks beim Löschen

Für jedes Objekt, das dabei gelöscht wird, laufen die Hooks mit der Methode DELETE: für das angesprochene Objekt und für jedes abhängige Kind, jeweils mit den Hooks seines Modells.

  1. 1
    CDMS
    geht das Objekt und seine abhängigen Kinder durch und merkt für jedes die DELETE-Hooks vor
  2. 2
    Hook
    Before-Hooks laufen, das Objekt hat noch alle eigenen Felder
    Hier kannst du prüfen, ob gelöscht werden darf, oder abhängige Daten außerhalb von CDMS aufräumen. Wirft der Hook einen Fehler, scheitert die Anfrage, und die Datenbank bleibt unverändert.
  3. 3
    CDMS→Database
    entfernt die Zeilen
  4. 4
    Hook
    After-Hooks laufen
  5. 5
    CDMS→Database
    schreibt alles in die Datenbank und committet

Ein Objekt, das nur gelöst wird (Beziehung ohne DELETE-Flag), wird nicht gelöscht. Für es laufen keine DELETE-Hooks.

Varianten

Wie gelöscht wird

Wann: DELETE {basis}/delete/{id}

  1. 1
    Client→CDMS
    schickt DELETE /company/delete/c4…, ohne Körper
  2. 2
    CDMS
    prüft Sichtbarkeit, dann die Löschrolle
  3. 3
    CDMS→Database
    löscht das Objekt, seine abhängigen Kinder und löst alle anderen Beziehungen

Ergebnis: 200 ohne Körper.

Wann: DELETE {basis}/delete, ohne id

  1. 1
    CDMS→Database
    sucht das eine Objekt selbst
  2. 2
    CDMS
    keins da → nichts zu tun, 200
  3. 3
    CDMS
    vorhanden → prüft die Löschrolle und löscht es wie ein normales Objekt, mit Kaskade und Hooks

Ergebnis: Danach ist ein neues create wieder möglich. Siehe Singletons.

Wann: DELETE {basis}/delete/{id} an der Hub-API eines abstrakten Modells

  1. 1
    Client→CDMS
    schickt nur die id, kein @type
  2. 2
    CDMS→Database
    liest den gespeicherten Typ zur id nach
  3. 3
    CDMS
    gibt es die id nicht → 404
  4. 4
    CDMS
    gibt die Anfrage an die API des Untertyps weiter: Sichtbarkeit, Löschrolle, Kaskade und Hooks sind die des Untertyps

Ergebnis: Um einen Privatkunden über /crm/kunde/delete/{id} zu löschen, brauchst du die Löschrolle des Privatkunden. Siehe Abstrakte Modelle.

Entscheidungstabelle

Ergebnis eines DELETE
Zeile für dich sichtbarLöschrolle des ModellsLöschrolle jedes abhängigen KindesErgebnis
nein––404 not-found|<Dto>|<id>, nichts gelöscht
janein–403 missing-permission|<rolle>, nichts gelöscht
jajafehlt bei einem Kind403 mit der Rolle des Kindes, nichts gelöscht
jajaja200, Objekt und abhängige Kinder gelöscht

Bei ausgeschaltetem Strict Mode heißt der Schlüssel bei fehlender Rolle missing-delete-role, der Status bleibt 403. Löschen wird also nie still übergangen.

Zweimal löschen

Eine gelöschte Zeile gibt es nicht mehr. Ein zweites DELETE mit derselben id findet nichts und liefert 404. Für einen Client, der eine Anfrage wiederholt, weil die erste Antwort ausblieb, heißt 404 beim zweiten Versuch meistens: Das Objekt ist schon weg. Siehe Darf der Client wiederholen?

Fallen

Wie es weitergeht

Quellen im Code und in der Wissensdatenbank
  • CDMS/cdms-system-layer – AbstractSystemLayer.deleteObject, AbstractSystemSingletonLayer.deleteObject, AbstractLayer.assertVisibleForWrite, recursiveDelete
  • CDMS/cdms-authorization – AbstractAuthorizationLayer.deleteAccessAllowedByClass, classAccess
  • CDMS/cdms-rest-api – AbstractRestApi.deleteObject, AbstractRestSingletonApi.deleteObject, AbstractHubApi.delete
  • CDMS/cdms-generator – ApiProcessor, ApiSingletonProcessor, ApiHubProcessor (getDeleteMethod)
  • CDMS/cdms-persistence-database – AbstractDatabasePersistence.deleteObject, flush
  • CDMS/cdms-integrationtest – AbstractRoleDenialTest, AbstractDataFilterTest, AbstractAuditTrailTest, AbstractRecursiveDelete
  • documentation/05-api-guide/06-schreiben.md, 20-api/04-schreibsemantik.md
Suchen