MIXED_DML_OPERATION bei Salesforce-Deployments beheben

Apex versucht, ein Setup-Objekt wie User oder Group und ein Nicht-Setup-Objekt in derselben Transaktion zu ändern.

Tritt auf bei: Apex-Laufzeit, meist innerhalb der für ein Deployment erforderlichen Testausführung

Was das bedeutet

MIXED_DML_OPERATION ist eine Apex-Laufzeit-Exception: Salesforce erlaubt kein DML auf einem Setup-Objekt (User, Group, GroupMember und ähnliche) und einem Nicht-Setup-Objekt (Account, Contact, benutzerdefinierte Objekte) innerhalb derselben Transaktion. Es tritt am häufigsten während der von einem Produktions-Deployment geforderten Apex-Testausführung auf und wird dann zu einem das Deployment blockierenden Testfehler.

Die Einschränkung besteht, weil Setup-Objekte den Zugriff auf Datensatzebene und die Freigabe ändern können, und Salesforce lässt nicht zu, dass eine einzelne Transaktion gleichzeitig ändert, wer Daten sehen kann, und diese Daten schreibt, weshalb es bei der Behebung immer um Transaktionsgrenzen geht, nie um den Inhalt der Datensätze.

Diagnose

Häufige Ursachen

Test-Setup erstellt einen User und Business-Datensätze zusammen
Eine Testmethode fügt einen User ein und fügt dann, in derselben Transaktion, ein Account oder einen anderen Business-Datensatz ein, ohne das DML zu isolieren.
Trigger weist eine Queue- oder Gruppenmitgliedschaft zu
Ein Trigger auf einem Business-Objekt fügt ein GroupMember ein oder aktualisiert die Freigabe, während andere Business-Datensätze im selben Kontext gespeichert werden.
Setup-Objekt-DML läuft inline statt isoliert
Code, der das Setup-Objekt-DML in eine eigene Transaktion isolieren sollte, führt es stattdessen im selben Kontext wie Business-Objekt-DML aus.

Die Lösung

  1. Setup-Objekt-DML in eine eigene Transaktion verschieben
    Umschließen Sie das Einfügen von User oder Group mit einer Future-Methode oder isolieren Sie es anderweitig, sodass es committet wird, bevor das Business-Objekt-DML läuft.
    @future
    private static void insertUserAsync(String jsonUser) {
        User u = (User) JSON.deserialize(jsonUser, User.class);
        insert u;
    }
  2. Test.startTest() und Test.stopTest() verwenden, um die Transaktion aufzuteilen
    Platzieren Sie in Tests das Setup-Objekt-DML vor Test.startTest(), damit es innerhalb seiner eigenen Transaktionsgrenze vor dem Business-Objekt-DML läuft.
  3. Setup- und Business-Objekt-Inserts niemals im selben Trigger-Kontext kombinieren
    Refaktorisieren Sie die Automatisierung so, dass Setup-Objekt-Änderungen, wie User-Provisioning oder Gruppenmitgliedschaft, niemals eine Transaktion mit Business-Datensatz-DML teilen.
In der Praxis

Wie Serpent das verhindert

Die CI-Pipeline von Serpent führt die vollständige Apex-Testsuite bei jeder Aufgabe aus, bevor sie für einen Merge in Frage kommt, sodass ein MIXED_DML_OPERATION-Testfehler bei der Aufgabe auftaucht, die ihn verursacht hat, nicht bei einer Produktionsfreigabe. Siehe die Bibliothek der Salesforce-Deploymentfehler.

No-Code-CI/CD-Pipeline-Builder in Serpent

Prävention

Test-Users immer in @TestSetup einfügen, vor jedem Business-Datensatz-DML
Strukturieren Sie Testklassen so, dass die Erstellung von Setup-Objekten in einer eigenen @TestSetup-Methode erfolgt, vollständig getrennt von der zu testenden Geschäftslogik.
Änderungen an Gruppen- und Sharing-Mitgliedschaft in einer eigenen Service-Methode isolieren
Leiten Sie alle GroupMember- und Sharing-Datensatz-DML über ein einziges, asynchron aufgerufenes Utility, damit Geschäftslogik nie versehentlich eine Transaktion damit teilt.
Setup-Objekt-DML im Code-Review kennzeichnen
Behandeln Sie jedes Insert oder Update auf User, Group oder GroupMember als Review-Hinweis, um zu bestätigen, dass es korrekt vom Business-Objekt-DML in derselben Methode isoliert ist.
Häufige Fragen

MIXED_DML_OPERATION, beantwortet

Warum schlägt MIXED_DML_OPERATION nur beim Deployment fehl, nicht bei normaler Nutzung?
Es schlägt fehl, wann immer der Codepfad ausgeführt wird, aber Deployments in die Produktion erfordern, dass alle Apex-Tests bestehen, sodass ein Test, der diese Exception auslöst, die gesamte Freigabe blockiert, selbst wenn der zugrunde liegende Code diesen Pfad in der Produktion selten ausführt.
Welche Objekte zählen für diese Regel als Setup-Objekte?
User, Group, GroupMember, UserRole und eine Handvoll verwandter Sharing- und Permission-Objekte. Die meisten Business- und benutzerdefinierten Objekte sind nicht betroffen und können frei miteinander gemischt werden.
Vermeidet System.runAs() in einem Test diesen Fehler?
Nein, System.runAs() ändert den ausführenden Benutzerkontext für Berechtigungstests; es isoliert keine Transaktionsgrenze, wie es ein Future-Aufruf oder Test.startTest() tun.

Kostenlos starten. Keine Kreditkarte, keine Installation, keine Verpflichtung.

In unter 15 Minuten eingerichtet. Keine DevOps-Einstellung nötig.

Neugierig auf schnelleres Shipping, bevor Sie einsteigen? Sprechen wir

Unverbindlich.