= delete()
:description: Löscht ein ECM-Objekt via dms.XMLDelete. Standard: Soft-Delete (Papierkorb); mit hard_delete=True permanentes Löschen. Akzeptiert Modellinstanz oder (object_id, object_type).
:keywords: delete, XMLDelete, Papierkorb, hard_delete, Soft-Delete, object_id, object_type
:page-tags: api, dms

Löscht ein bestehendes ECM-Objekt.
Das Objekt wird standardmäßig in den Papierkorb verschoben — mit `hard_delete=True` wird es dauerhaft entfernt.

Das zu löschende Objekt kann entweder über eine Modell-Instanz oder direkt über `object_id` und `object_type` angegeben werden.

== Signatur

[tabs]
====
Sync::
+
[source,python]
----
ecm.dms.delete(
    model: ECMFolderModel | ECMRegisterModel | ECMDocumentModel | int,
    object_type: int | str | None = None,
    *,
    hard_delete: bool = False,
    delete_cascading: bool = False,
) -> None
----

Async::
+
[source,python]
----
await ecm.dms.delete(
    model: ECMFolderModel | ECMRegisterModel | ECMDocumentModel | int,
    object_type: int | str | None = None,
    *,
    hard_delete: bool = False,
    delete_cascading: bool = False,
) -> None
----
====

== Parameter

[cols="1,1,3"]
|===
|Parameter |Standard |Beschreibung

|`model`
|—
|Das zu löschende Objekt — entweder eine Modell-Instanz mit gesetzter `id`
oder eine plain `int`-ID (dann muss `object_type` angegeben werden).

|`object_type`
|`None`
|Nur erforderlich, wenn `model` ein `int` ist. Identifiziert den Objekttyp:
`int` für eine numerische Typ-ID oder `str` für den internen Namen.

|`hard_delete`
|`False`
|Bei `True` wird das Objekt dauerhaft gelöscht (`HARDDELETE=1`) und nicht in den Papierkorb verschoben.

|`delete_cascading`
|`False`
|Bei `True` werden alle Kindobjekte rekursiv mitgelöscht (`DELETECASCADING=1`).
Sinnvoll für Ordner oder Register mit Unterstruktur.
|===

== Ausnahmen

`ValueError`:: `model` ist ein `int`, aber `object_type` wurde nicht angegeben.
`ValueError`:: `model` ist eine Modell-Instanz mit `id = None`.

== Beispiele

=== Objekt nach Abfrage löschen

Der häufigste Anwendungsfall: Objekt zuerst laden, dann löschen.

[tabs]
====
Sync::
+
[source,python]
----
folder = ecm.dms.get(InvoiceFolder, 12345)
ecm.dms.delete(folder)
----

Async::
+
[source,python]
----
folder = await ecm.dms.get(InvoiceFolder, 12345)
await ecm.dms.delete(folder)
----
====

=== Löschen per object_id und internem Namen

Ist die ID bekannt, muss das Objekt nicht vollständig geladen werden.
Der interne Name des Objekttyps wird als `object_type` übergeben:

[tabs]
====
Sync::
+
[source,python]
----
ecm.dms.delete(12345, "InvoiceFolder")
----

Async::
+
[source,python]
----
await ecm.dms.delete(12345, "InvoiceFolder")
----
====

=== Löschen per object_id und numerischer Typ-ID

Alternativ kann die numerische Typ-ID verwendet werden, falls der interne Name nicht bekannt ist:

[tabs]
====
Sync::
+
[source,python]
----
# Typ-ID z.B. aus get_object_type_by_id() ermitteln
type_id = ecm.dms.get_object_type_by_id(12345)
ecm.dms.delete(12345, type_id)
----

Async::
+
[source,python]
----
type_id = await ecm.dms.get_object_type_by_id(12345)
await ecm.dms.delete(12345, type_id)
----
====

=== Dauerhaft löschen (ohne Papierkorb)

Mit `hard_delete=True` wird das Objekt endgültig entfernt und kann nicht wiederhergestellt werden:

[tabs]
====
Sync::
+
[source,python]
----
ecm.dms.delete(12345, "InvoiceFolder", hard_delete=True)
----

Async::
+
[source,python]
----
await ecm.dms.delete(12345, "InvoiceFolder", hard_delete=True)
----
====

=== Ordner mit gesamter Unterstruktur löschen

Mit `delete_cascading=True` werden alle untergeordneten Register und Dokumente mitgelöscht:

[tabs]
====
Sync::
+
[source,python]
----
ecm.dms.delete(42, "InvoiceFolder", delete_cascading=True)
----

Async::
+
[source,python]
----
await ecm.dms.delete(42, "InvoiceFolder", delete_cascading=True)
----
====

=== Alle Treffer einer Abfrage löschen

Objekte stapelweise löschen: in jeder Iteration wird eine begrenzte Anzahl abgerufen und gelöscht,
bis keine Treffer mehr zurückkommen. So wird der Speicher nicht unnötig belastet und das
seitenbasierte Paging von `stream()` umgangen.

[tabs]
====
Sync::
+
[source,python]
----
while True:
    batch = (
        ecm.dms.select(InvoiceFolder)
        .where(InvoiceFolder.Year == 2020)
        .limit(100)
        .execute()
    )
    if not batch:
        break
    for folder in batch:
        ecm.dms.delete(folder, hard_delete=True, delete_cascading=True)
----

Async::
+
[source,python]
----
while True:
    batch = await (
        ecm.dms.select(InvoiceFolder)
        .where(InvoiceFolder.Year == 2020)
        .limit(100)
        .execute()
    )
    if not batch:
        break
    for folder in batch:
        await ecm.dms.delete(folder, hard_delete=True, delete_cascading=True)
----
====

== Siehe auch

* xref:api/dms/get.adoc[get()] — Einzelnes Objekt anhand seiner ID laden
* xref:api/dms/select.adoc[select()] — Objekte mit typisiertem Modell abfragen
* xref:api/dms/insert.adoc[insert()] — Neues Objekt anlegen
