MIXED_DML_OPERATION in Salesforce-deployments oplossen

Apex probeert een setup-object, zoals User of Group, en een non-setup-object in dezelfde transactie te wijzigen.

Komt voor bij: Apex-runtime, meestal tijdens de testuitvoering die een deploy vereist

Wat het betekent

MIXED_DML_OPERATION is een Apex-runtime-exception: Salesforce staat geen DML toe op een setup-object (User, Group, GroupMember en vergelijkbare) en een non-setup-object (Account, Contact, custom objects) binnen dezelfde transactie. Dit komt meestal naar voren tijdens de Apex-testuitvoering die een productiedeployment vereist, wat leidt tot een deployment-blokkerende testfout.

De restrictie bestaat omdat setup-objecten record-niveau toegang en sharing kunnen wijzigen, en Salesforce staat niet toe dat één transactie zowel bepaalt wie data kan zien als die data tegelijk wegschrijft, wat de reden is dat de oplossing altijd over transactiegrenzen gaat, nooit over de inhoud van de records.

Diagnose

Veelvoorkomende oorzaken

Testsetup maakt een user en business-records samen aan
Een testmethode voegt een User toe en voegt vervolgens, in dezelfde transactie, een Account of ander business-record toe zonder de DML te isoleren.
Trigger wijst een queue of groepslidmaatschap toe
Een trigger op een business-object voegt een GroupMember toe of werkt sharing bij terwijl andere business-records in dezelfde context worden opgeslagen.
Setup-object-DML draait inline in plaats van geïsoleerd
Code die de setup-object-DML zou moeten isoleren in een eigen transactie, voert deze in plaats daarvan uit in dezelfde context als business-object-DML.

De oplossing

  1. Verplaats setup-object-DML naar een eigen transactie
    Verpak de User- of Group-insert in een future-methode, of isoleer deze anderszins, zodat deze commit voordat de business-object-DML draait.
    @future
    private static void insertUserAsync(String jsonUser) {
        User u = (User) JSON.deserialize(jsonUser, User.class);
        insert u;
    }
  2. Gebruik Test.startTest() en Test.stopTest() om de transactie te splitsen
    Plaats in tests de setup-object-DML vóór Test.startTest(), zodat deze binnen zijn eigen transactiegrens draait vóór de business-object-DML.
  3. Combineer setup- en business-object-inserts nooit in één triggercontext
    Refactor automatisering zodat setup-object-wijzigingen, zoals user provisioning of groepslidmaatschap, nooit een transactie delen met business-record-DML.
In de praktijk

Hoe Serpent dit voorkomt

De CI-pipeline van Serpent voert de volledige Apex-testsuite uit op elke taak voordat deze in aanmerking komt voor merge, zodat een MIXED_DML_OPERATION-testfout naar voren komt op de taak die deze veroorzaakte, niet op een productierelease. Zie de Salesforce-deploymentfoutenbibliotheek.

No-code CI/CD-pipelinebuilder in Serpent

Preventie

Voeg testgebruikers altijd toe in @TestSetup, vóór elke business-record-DML
Structureer testclasses zodat het aanmaken van setup-objecten plaatsvindt in een aparte @TestSetup-methode, volledig gescheiden van de bedrijfslogica die wordt getest.
Isoleer wijzigingen aan groeps- en sharinglidmaatschap in een eigen servicemethode
Route alle GroupMember- en sharing-record-DML via één utility die asynchroon wordt aangeroepen, zodat bedrijfslogica er nooit per ongeluk een transactie mee deelt.
Markeer setup-object-DML in code review
Behandel elke insert of update op User, Group of GroupMember als een reviewsignaal om te bevestigen dat deze correct is geïsoleerd van business-object-DML in dezelfde methode.
Veelgestelde vragen

MIXED_DML_OPERATION, beantwoord

Waarom mislukt MIXED_DML_OPERATION alleen tijdens deployment, niet bij normaal gebruik?
Het mislukt telkens wanneer het codepad wordt uitgevoerd, maar deployments naar productie vereisen dat alle Apex-tests slagen, dus een test die deze exception veroorzaakt blokkeert de hele release, zelfs als de onderliggende code dat pad zelden uitvoert in productie.
Welke objecten tellen als setup-objecten voor deze regel?
User, Group, GroupMember, UserRole en een handvol gerelateerde sharing- en permission-objecten. De meeste business- en custom objecten zijn niet getroffen en kunnen vrij met elkaar worden gecombineerd.
Voorkomt System.runAs() in een test deze fout?
Nee, System.runAs() wijzigt de uitvoerende gebruikerscontext voor permissietests; het isoleert geen transactiegrens zoals een future-aanroep of Test.startTest() dat doet.

Start gratis. Geen creditcard, geen installatie, geen verplichting.

Binnen 15 minuten ingesteld. Geen DevOps-aanwerving nodig.

Benieuwd naar sneller releasen voordat je instapt? Laten we praten

Vrijblijvend.