= update()
:description: Schreibt geänderte Felder eines ECM-Objekts zurück (dms.XMLUpdate). Überträgt nur modifizierte Felder. Erfordert eine zuvor geladene Instanz mit gesetzter object_id.
:keywords: update, XMLUpdate, Felder aktualisieren, object_id, modifizierte Felder, ECMFolderModel
:page-tags: api, dms

Aktualisiert ein bestehendes Objekt auf dem Server. Intern wird `dms.XMLUpdate` verwendet. Die übergebene Modell-Instanz wird nicht verändert.

Wurden keine Felder geändert und keine Dateien übergeben, wird der Server-Aufruf standardmäßig übersprungen. Mit `force=True` kann der Aufruf erzwungen werden.

Wird die aktualisierte Instanz direkt nach dem Speichern benötigt, ist xref:api/dms/update_and_get.adoc[update_and_get()] die kompaktere Alternative.

== Signatur

[tabs]
====
Sync::
+
[source,python]
----
ecm.dms.update(
    model: T,
    files: list[JobRequestFile] | None = None,
    replace_files: bool = True,
    force: bool = False,
    *,
    check_mandatory: bool = True,
) -> None
----

Async::
+
[source,python]
----
await ecm.dms.update(
    model: T,
    files: list[JobRequestFile] | None = None,
    replace_files: bool = True,
    force: bool = False,
    *,
    check_mandatory: bool = True,
) -> None
----
====

== Parameter

[cols="1,1,3"]
|===
|Name |Typ |Beschreibung

|`model`
|`ECMFolderModel \| ECMRegisterModel \| ECMDocumentModel`
|Die zu aktualisierende Modell-Instanz. Muss vom Server geladen worden sein, damit `model.system.id` gesetzt ist.

|`files`
|`list[JobRequestFile] \| None`
|Optionale Dateiliste für das Dokument. Nur für `ECMDocumentModel` erlaubt — bei Ordner- oder Register-Modellen wird `TypeError` geworfen. Standard: `None`.

|`replace_files`
|`bool`
|Wenn `True` (Standard) und `files` übergeben wurden, ersetzen die neuen Dateien die vorhandenen Dokumentdateien (`REPLACEFILES=1`). Wenn `False`, werden die Dateien den bestehenden hinzugefügt. Nur wirksam für `ECMDocumentModel` mit `files`.

|`force`
|`bool`
|Wenn `True`, wird der Server-Aufruf immer ausgeführt, auch wenn keine Änderungen erkannt wurden. Standard: `False`.

|`check_mandatory`
|`bool`
|Wenn `True` (Standard), wird clientseitig geprüft, ob alle als `mandatory=True` deklarierten `ECMField`-Felder einen Wert haben. Bei `False` wird die client- und serverseitige Pflichtfeldprüfung deaktiviert (`CHECKOBLIGATION=0`).
|===

== Rückgabewert

`None`

== Automatisches Überspringen

Wenn alle der folgenden Bedingungen zutreffen, wird der Server-Aufruf ohne Fehler übersprungen:

* `force=False` (Standard)
* `model.system.is_modified` ist `False` — keine Felder wurden geändert
* `files` ist `None`

Das Änderungsprotokoll (`is_modified`, `modified_fields`) wird vom Modell automatisch beim Setzen von Feldwerten geführt. Entfernte Tabellenzeilen werden ebenfalls erkannt: Wurden Zeilen gelöscht, wird die Option `REPLACETABLEFIELDS=1` automatisch gesetzt.

== Ausnahmen

`ValueError`:: `model.system.id` ist `None` (Objekt wurde nicht vom Server geladen) oder `check_mandatory=True` und ein Pflichtfeld ist nicht gesetzt.
`TypeError`:: `files` wurde für ein Ordner- oder Register-Modell übergeben.

== Beispiele

=== Einfaches Feldupdate

[tabs]
====
Sync::
+
[source,python]
----
folder = ecm.dms.get(InvoiceFolder, 12345)
folder.Title = "Rechnung 2024 (aktualisiert)"
ecm.dms.update(folder)
----

Async::
+
[source,python]
----
folder = await ecm.dms.get(InvoiceFolder, 12345)
folder.Title = "Rechnung 2024 (aktualisiert)"
await ecm.dms.update(folder)
----
====

=== Dokument mit Datei ersetzen

[tabs]
====
Sync::
+
[source,python]
----
from ecmind_blue_client.rpc import JobRequestFileFromPath

doc = ecm.dms.get(InvoiceDocument, 42)
doc.Title = "Rechnung Nr. 42 (korrigiert)"
ecm.dms.update(
    doc,
    files=[JobRequestFileFromPath("/tmp/rechnung_v2.pdf")],
    replace_files=True,  # vorhandene Dateien ersetzen (Standard)
)
----

Async::
+
[source,python]
----
from ecmind_blue_client.rpc import JobRequestFileFromPath

doc = await ecm.dms.get(InvoiceDocument, 42)
doc.Title = "Rechnung Nr. 42 (korrigiert)"
await ecm.dms.update(
    doc,
    files=[JobRequestFileFromPath("/tmp/rechnung_v2.pdf")],
    replace_files=True,
)
----
====

=== Datei anhängen statt ersetzen

[tabs]
====
Sync::
+
[source,python]
----
from ecmind_blue_client.rpc import JobRequestFileFromPath

doc = ecm.dms.get(InvoiceDocument, 42)
ecm.dms.update(
    doc,
    files=[JobRequestFileFromPath("/tmp/anhang.pdf")],
    replace_files=False,  # Datei hinzufügen, bestehende behalten
)
----

Async::
+
[source,python]
----
from ecmind_blue_client.rpc import JobRequestFileFromPath

doc = await ecm.dms.get(InvoiceDocument, 42)
await ecm.dms.update(
    doc,
    files=[JobRequestFileFromPath("/tmp/anhang.pdf")],
    replace_files=False,
)
----
====

=== Update erzwingen

Nützlich, wenn externe Logik eine Neuübermittlung erfordert, obwohl keine Felder geändert wurden:

[tabs]
====
Sync::
+
[source,python]
----
folder = ecm.dms.get(InvoiceFolder, 12345)
# keine Feldänderung — ohne force=True würde der Aufruf übersprungen
ecm.dms.update(folder, force=True)
----

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

=== Pflichtfeldprüfung deaktivieren

[tabs]
====
Sync::
+
[source,python]
----
folder = ecm.dms.get(InvoiceFolder, 12345)
folder.Title = None  # Pflichtfeld leeren
# check_mandatory=False: kein Fehler, Pflichtfeldprüfung auch serverseitig deaktiviert
ecm.dms.update(folder, check_mandatory=False)
----

Async::
+
[source,python]
----
folder = await ecm.dms.get(InvoiceFolder, 12345)
folder.Title = None
await ecm.dms.update(folder, check_mandatory=False)
----
====

== Siehe auch

* xref:api/dms/update_and_get.adoc[update_and_get()] — kombiniert `update()` und `get()` in einem Aufruf, wenn die aktualisierte Instanz benötigt wird
* xref:api/dms/insert.adoc[insert()] — legt ein neues Objekt an
* xref:api/dms/get.adoc[get()] — lädt ein einzelnes Objekt vom Server
