Erfassen Sie Ihre Fortschritte
Trailhead-Startseite
Trailhead-Startseite

Verstehen des Ausführungskontextes

Lernziele

Nachdem Sie diese Lektion abgeschlossen haben, sind Sie in der Lage, die folgenden Aufgaben auszuführen:

  • Wissen über die Methoden, die zum Aufrufen eines Apex zu verwenden sind
  • Schreiben eines Auslösers für ein Salesforce-Objekt
  • Durch Ausführen von Code in der Entwicklerkonsole beobachten, wie der Ausführungskontext funktioniert
  • Verstehen der Auswirkungen von Obergrenzen auf Designmuster
  • Verstehen der Bedeutung der Arbeit mit Massenvorgängen

Ausführungskontext

Bei ASP.NET-Anwendungen wird Code im Kontext einer Anwendungsdomäne ausgeführt. In der Welt der Lightning-Plattform wird Code in einem Ausführungskontext ausgeführt. Kurz gesagt stellt dieser Kontext die Zeit zwischen der Ausführung des Codes und seinem Ende dar. Was Sie unbedingt verstehen müssen, ist, dass der Apex-Code, den Sie schreiben, nicht immer der einzige Code ist, der ausgeführt wird.

Um zu verstehen, wie das funktioniert, müssen Sie die Möglichkeiten kennen, auf die Apex-Code auf der Plattform ausgeführt werden kann.

Methoden zum Aufrufen von Apex-Code
Methode Beschreibung
Datenbankauslöser Wird für ein bestimmtes Ereignis zu einem benutzerdefinierten oder einem Standardobjekt aufgerufen.
Anonymes Apex Codeausschnitte werden spontan in der Entwicklerkonsole und anderen Tools ausgeführt.
Asynchrones Apex Tritt beim Ausführen eines Future- oder eines Queueable Apex, beim Ausführen eines Batchauftrags oder beim Planen eines Apex zur Ausführung in einem bestimmten Intervall auf.
Webservices Code, der mittels der Webservices SOAP oder REST zur Verfügung gestellt wird.
E-Mail-Services Code, der zur Verarbeitung eingehender E-Mails eingerichtet wird.
Visualforce- oder Lightning-Seiten Visualforce-Steuerfelder und Lightning-Komponenten können Apex-Code automatisch ausführen oder wenn ein Benutzer eine Aktion initiiert, wie z. B. wenn er auf eine Schaltfläche klickt. Lightning-Komponenten können außerdem durch Lightning-Prozesse und Flows ausgeführt werden.

Es kann nicht nur Apex-Code aufgerufen werden, sondern es können auch alle Aktionen wie z. B. das Erstellen einer neuen Aufgabe, das Senden einer E-Mail, das Durchführen eines Feld-Updates oder das Senden einer Nachricht mithilfe einer der deklarativen Plattformfunktionen ausgelöst werden. Diese Aktionen werden ebenfalls in einem Ausführungskontext ausgeführt.

Eine weiterer wichtiger Punkt ist der Kontext des Benutzers, der den Apex-Code ausführt. Standardmäßig werden Apex-Codes in einem Systemkontext ausgeführt. Apex-Code hat Zugang zu allen Objekten und Feldern. Objektberechtigungen, Sicherheit auf Feldebene und Freigaberegeln werden finden auf den aktuellen Benutzer keine Anwendung. Sie können das Schlüsselwort 'with sharing' verwenden, um anzugeben, dass die Freigaberegeln bei dem aktuellen Benutzer für eine Klasse berücksichtigt werden. Dieser Punkt ist wichtig, sodass Sie unbedingt den Abschnitt Verwendung der Schlüsselwörter 'with sharing' oder 'without sharing' lesen sollten.

Wichtige Grundlagen zu Auslösern

Bevor Sie mehr über den Ausführungskontext erfahren, gehen wir zunächst einen Schritt zurück, um Sie in die Welt der Datenbankauslöser einzuführen. Ähnlich den Auslösern in SQL Server führen Apex-Datenbankauslöser vor oder nach Ereignissen bei Datensätzen in Salesforce eine Programmierlogik aus. Beim Definieren des Auslösers können Sie mehrere der folgenden Ereignisse angeben:

  • before insert
  • before update
  • before delete
  • after insert
  • after update
  • after delete
  • after undelete

Die grundlegende Syntax eines Auslösers sieht wie folgt aus:

trigger TriggerName on ObjectName (trigger_events) {
   // code_block
}

Jetzt wissen wir, wie gerne .NET-Entwickler Probleme mit Code lösen, aber hier kommt noch einer richtig toller Produktivitätstipp für Sie. Am besten greifen Sie nur auf einen Auslöser zurück, wenn Sie absolut sicher sind, dass derselbe Vorgang nicht mit einem unserer Point-and-Click-Automatisierungstools umzusetzen ist.

Um Ihnen das Leben zu erleichtern, bietet die Salesforce-Plattform mehrere Automatisierungstools, wie z. B. Lightning-Prozessgenerator und Lightning Flow Builder, mit denen Sie Ihre Geschäftslogik verwalten können, ohne Code schreiben zu müssen. In den meisten Fällen sind Aufgaben, die früher nur mit einem Auslöser erfüllt werden konnten, heutzutage besser geeignet für eines der Automatisierungstools.

Hinweis

Hinweis

Wenn Sie als Entwickler neu auf der Plattform sind, nehmen Sie sich auf jeden Fall Zeit und informieren sich über das Modul Lightning Flow im Trail "Entwickler – Anfänger", bevor Sie einen Auslöser erstellen. Wir sind ziemlich sicher, dass Sie nicht als der- oder diejenige in die Geschichte eingehen möchten, der oder die der Salesforce-Organisation jede Menge unnötigen technischen Mehraufwand beschert hat.

Markieren von Ausführungskontext

Um den Ausführungskontext besser zu verstehen, schauen wir uns einmal genau die Erstellung eines Apex-Datenbankauslösers an, der eine Opportunity erstellt, wenn ein neuer Account angelegt wird. Dieser Auslöser ruft eine Methode aus einer Handler-Klasse auf, sodass wir diese zunächst erstellen müssen.

  1. Wählen Sie unter "Setup" Ihr Name > Developer Console aus, um die Entwicklerkonsole zu öffnen.
  2. Wählen Sie in der Developer Console File > New > Apex Class aus.
  3. Geben Sie AccountHandler als Klassennamen ein und klicken Sie auf OK.
  4. Löschen Sie den vorhandenen Code und fügen Sie den folgenden Ausschnitt ein:

    public with sharing class AccountHandler {
    
        public static void CreateNewOpportunity(List<Account> accts) {
    
            for (Account a : accts) {
                Opportunity opp = new Opportunity();
                opp.Name = a.Name + ' Opportunity';
                opp.AccountId = a.Id;
                opp.StageName = 'Prospecting';
                opp.CloseDate = System.Today().addMonths(1);
                insert opp;
            }
        }
    
    }
    
  5. Drücken Sie Strg + S, um die Klasse zu speichern.

Hinweis

Hinweis

Es gilt als bewährte Vorgehensweise, pro Objekt nur einen Auslöser zu verwenden, was im folgenden Beispiel dargestellt ist. Anschließend können Sie kontextspezifische Handler-Methoden innerhalb von Auslösern verwenden, um Auslöser ohne Logik zu erstellen. Indem Sie so vorgehen, können Sie die Fallstricke umgehen, in denen neue Entwickler sich gerne verfangen. Um mehr über diese Verfahren zu erfahren, lesen Sie den Abschnitt zu Auslöser-Frameworks und die bewährten Vorgehensweisen für Apex-Auslöser.

Jetzt, da wir die Handler-Klasse haben, erstellen wir den Account-Auslöser.

  1. Wählen Sie in der Entwicklerkonsole File > New > Apex Trigger aus.
  2. Geben Sie als Namen AccountTrigger ein und wählen Sie als sObject Account aus.
  3. Klicken Sie auf Submit (Senden).
  4. Löschen Sie den vorhandenen Code und fügen Sie den folgenden Ausschnitt ein:

    trigger AccountTrigger on Account (before insert, before update, before
        delete, after insert, after update, after delete,  after undelete) {
    
        if (Trigger.isAfter && Trigger.isInsert) {
            AccountHandler.CreateNewOpportunity(Trigger.New);
        }
    }
    
  5. Drücken Sie Ctrl + S, um Ihren Auslöser zu speichern.

Um den Durchgang abzuschließen, führen wir anonymen Code aus, um einen Benutzer zu simulieren, der über die Salesforce-Oberfläche einen neuen Account anlegt. Denken Sie daran: Apex-Code kann auf verschiedene Arten ausgeführt werden.

  1. Wählen Sie unter "Setup" Ihr Name > Developer Console aus, um die Entwicklerkonsole zu öffnen.
  2. Klicken Sie auf Debug > Open Execute Anonymous Window.
  3. Löschen Sie den vorhandenen Code und fügen Sie den folgenden Ausschnitt ein:

    Account acct = new Account(
        Name='Test Account 2',
        Phone='(415)555-8989',
        NumberOfEmployees=50,
        BillingCity='San Francisco');
    insert acct;
    
  4. Stellen Sie sicher, dass die Option 'Open Log' ausgewählt ist, und klicken Sie auf Execute. Auf einer neuen Registerkarte wird das Ausführungsprotokoll angezeigt. Lassen Sie es geöffnet, sodass Sie es sich genau anschauen können.

Überprüfen des Ausführungsprotokolls

Bitte beachten Sie, dass die erste Zeile im Ausführungsprotokoll dem Ereignis EXECUTION_STARTED entspricht, während die letzte Zeile das Ereignis EXECUTION_FINISHED ist. Alles dazwischen ist der Ausführungskontext.

Sehen wir uns nun genauer an, was geschieht. Ein Ereignis CODE_UNIT_STARTED weist darauf hin, dass der Code aus dem Fenster für die anonyme Ausführung gestartet wurde. Diese Zeile ist in der Abbildung unten rot markiert.

Screenshot des Debug-Protokolls in der Developer Console, in dem die 'code_unit_started'-Ereignisse hervorgehoben sind

Die zweite Zeile im Ereignis CODE_UNIT_STARTED, die markiert ist, zeigt an, wann der Code für das Ereignis BeforeInsert ausgeführt wurde.

Dies sehen Sie in der Abbildung, aber wenn Sie dem Vorgang mit Ihrer eigenen Instanz der Entwicklerkonsole folgen, scrollen Sie in den Ergebnissen weiter nach unten und suchen nach anderen Instanzen des Ereignisses CODE_UNIT_STARTED. Sie sollten mindestens eine weitere Instanz sehen, wenn Code für das Ereignis AfterInsert ausgeführt wurde. Wenn Sie Workflow-Regeln erstellt hatten, die ausgelöst wurden, als ein neuer Account angelegt wurde, werden auch diesen im Ausführungsprotokoll angezeigt. Dieser gesamte Code läuft in demselben Ausführungskontext und unterliegt daher denselben Obergrenzen.

Vielleicht fragen Sie sich, warum es so wichtig ist, dass Sie das alles verstehen? Nun ja, da Salesforce eine mandantenfähige Umgebung ist, sind diese Obergrenzen unerlässlich, wenn es darum geht, dass die einzelnen Instanzen einer Salesforce-Organisation nicht zu viele Ressourcen verbrauchen. Im Grunde bewahren sie das ganze System vor dem Abstürzen.

Arbeiten mit Grenzen

Und damit wären wir wieder beim Thema 'Arbeiten mit Grenzen'. Die beiden Grenzen, mit denen Sie wahrscheinlich am meisten zu tun haben werden, enthalten die Anzahl der SOQL-Abfragen oder DML-Anweisungen. Über sie stolpern tendenziell Entwickler, die neu auf der Plattform sind, sodass wir uns etwas zusätzliche Zeit nehmen wollen um zu sehen, wie sie zu umgehen sind.

Hinweis

Hinweis

Es gibt viele zu beachtende Grenzwerte, die sich gewöhnlich bei jeder Hauptversion ändern. Außerdem kommt es nicht allzu selten vor, dass Grenzwerte eher enger als weiter gefasst sind, sodass Sie immer auf dem neuesten Stand sein müssen. Öffnen Sie dazu in den Ressourcen den Link 'Execution Governors and Limits'.

Arbeiten per Massenvorgang

Viele Entwicklern sitzen einem Irrtum auf und entwickeln ihren eigenen Code, um mit einem einzigen Datensatz zu arbeiten. Sie finden schnell heraus, dass das auf der Lightning-Plattform ein großer Fehler sein kann.

Apex-Auslöser können bis zu 200 Objekte gleichzeitig empfangen. Zurzeit liegt die Synchrongrenze für die Gesamtzahl an SOQL-Abfragen bei 100 und für die Gesamtzahl an ausgegebenen DML-Anweisungen bei 150. Wenn Sie also einen Auslöser haben, der eine SOQL-Abfrage oder eine DML-Anweisung in einer Schleife ausführt, und dieser Auslöser für einen Massenvorgang in Gang gesetzt wurde, können Sie sich denken, was passiert, oder?

BUMM!!!

Genau richtig, Sie erhalten eine Fehlermeldung zur Obergrenze. Es ist möglich, dass Sie Code bereitstellen, der eine Weile problemlos läuft, bevor die Grenze entdeckt wird. Der Entwickler muss dann schnell zurückgehen und herausfinden, wie sich der Code 'in Masse verarbeiten' lässt. Es kommt nicht selten vor, dass dieser zweite Versuch länger dauert als das ursprüngliche Konzept. Um dieses Szenario zu vermeiden, konzipieren Sie Ihren Apex-Code so, dass er von Anfang an Massenvorgänge verarbeiten kann. Wie Sie dies tun können, lernen Sie im Modul Apex-Massenauslöser.

Vielleicht haben Sie es bemerkt, vielleicht auch nicht, aber bei dem Auslöser-Handlercode, den wir vorhin erstellt haben, kam kein Massenmuster zum Einsatz, sodass er für Grenzfehler anfällig ist. Zur Erinnerung: So sah der ursprüngliche Code aus.

public with sharing class AccountHandler {

    public static void CreateNewOpportunity(List<Account> accts) {

        for (Account a : accts) {
            Opportunity opp = new Opportunity();
            opp.Name = a.Name + ' Opportunity';
            opp.AccountId = a.Id;
            opp.StageName = 'Prospecting';
            opp.CloseDate = System.Today().addMonths(1);
            insert opp;
        }
    }

}

Bitte beachten Sie, dass sich der 'insert'-DML-Vorgang innerhalb der 'for'-Schleife befindet. Das ist sehr schlecht und sollte immer vermieden werden.

Glücklicherweise können wir diesen Code reparieren, indem wir ihn so ändern, dass er in eine Listenvariable im Innern der Schleife geschrieben wird und der Inhalt der Liste dann in einem Schritt eingefügt wird.

  1. Wählen Sie unter "Setup" Ihr Name > Developer Console aus, um die Entwicklerkonsole zu öffnen.
  2. Wählen Sie in der Developer Console File > Open aus.
  3. Wählen Sie für den Einheitentyp Classes aus. Wählen Sie als Einheit AccountHandler aus.
  4. Klicken Sie auf Öffnen.
  5. Löschen Sie den vorhandenen Code und fügen Sie den folgenden Ausschnitt ein:

    public with sharing class AccountHandler {
    
        public static void CreateNewOpportunity(List<Account> accts) {
    
            List<Opportunity> opps = new List<Opportunity>();
    
            for (Account a : accts) {
                Opportunity opp = new Opportunity();
                opp.Name = a.Name + ' Opportunity';
                opp.AccountId = a.Id;
                opp.StageName = 'Prospecting';
                opp.CloseDate = System.Today().addMonths(1);
                opps.add(opp);
            }
    
            if (opps.size() > 0) {
                insert opps;
            }
        }
    
    }
    
  6. Drücken Sie Strg + S, um die Klasse zu speichern.

Jetzt, da wir den Auslöser-Handlercode repariert haben, wollen wir ihn testen um sicherzustellen, dass der Auslöser 200 Datensätze handhaben kann. Sicherlich wissen Sie noch, dass es sich bewährt hat, Einheitentests zu schreiben um sicherzugehen, dass der Code funktioniert.

  1. Wählen Sie in der Developer Console File > New > Apex Class aus.
  2. Geben Sie als Klassennamen AccountTrigger_Test ein und klicken Sie auf OK.
  3. Löschen Sie den vorhandenen Code und fügen Sie den folgenden Ausschnitt ein:

    @isTest
    private class AccountTrigger_Test {
    
        @isTest static void TestCreateNewAccountInBulk() {
    
            // Test Setup data
            // Create 200 new Accounts
            List<Account> accts = new List<Account>();
            for(Integer i=0; i < 200; i++) {
                Account acct = new Account(Name='Test Account ' + i);
                accts.add(acct);
            }              
    
            // Perform Test
            Test.startTest();
            insert accts;                               
            Test.stopTest();
    
            // Verify that 200 new Accounts were inserted
            List<Account> verifyAccts = [SELECT Id FROM Account];
            System.assertEquals(200, verifyAccts.size());    
    
            // Also verify that 200 new Opportunities were inserted
            List<Opportunity> verifyOpps = [SELECT Id FROM Opportunity];                              
            System.assertEquals(200, verifyOpps.size());                             
        }
    }
    
  4. Drücken Sie Strg + S, um die Klasse zu speichern.

  5. Wählen Sie Test > New Run aus.

  6. Wählen Sie als Testklasse 'AccountTrigger_Test' aus und als Testmethode 'TestCreateNewAccountInBulk'.

  7. Klicken Sie auf Ausführen.

  8. Wählen Sie die Registerkarte Test aus und überprüfen Sie, ob der Test bis zum Ende fehlerfrei durchläuft, was Sie an einem grünen Häkchen in der Statusspalte erkennen.

Hinweis

Hinweis

Auch wenn wir noch nicht über Einheitentests gesprochen haben, machen Sie sich keine Gedanken. Sie funktionieren in der Lightning-Plattform im Großen und Ganzen so, wie sie es in .NET tun, nur einige Schlüsselwörter sind anders. Sie werden schnell verstehen, wie sie strukturiert sind. Erfahren Sie mehr über das Testen von Apex-Auslösern, indem Sie im Abschnitt "Ressourcen" auf den Link klicken.

Weitere Infos

Apex verwendet für die Handhabung von Ausnahmen einen vertrauten 'try-catch-finally'-Block. Ihre Catch-Anweisung und ein möglicher Rollback könnten sich jedoch unterscheiden, je nachdem, wo der Apex-Code ausgeführt wird. Klicken Sie im Abschnitt 'Ressourcen' auf den Link zu den bewährten Vorgehensweisen, wenn Sie es in Apex mit 'try', 'catch' und 'rollback' zu tun haben.

Etwas wie eine Anwendungs- oder Sitzungsvariable gibt es in der Lightning-Plattform nicht. Wenn Daten verschiedener Klassen weiterhin Bestand haben sollen, gibt es statische Variablen, aber denken Sie immer daran, dass statische Variablen in der Lightning-Plattform nicht so funktionieren, wie sie es in .NET tun. In der Welt der Lightning-Plattform kann eine statische Variable Informationen nur in einem einzelnen Ausführungskontext behalten, wenngleich noch weitere Optionen zum Verwalten von Daten über Auslöseraufrufe zur Verfügung stehen. Um mehr zu erfahren, schauen Sie sich in den Internetressourcen die Links zum erweiterten Apex an.

Wenn Sie mit Grenzen arbeiten, gibt es viele Kompromisse, die in Betracht gezogen werden müssen, insbesondere für die Entwickler von verwalteten Paketen. Nebenbei bemerkt verwenden Salesforce-Partner in der Regel verwaltete Pakete zum Vertreiben und Verkaufen von Anwendungen. In diesem Modul haben wir gerade eben einmal an der Oberfläche dessen gekratzt, was Sie wissen müssen. Wenn Sie es mit der Apex-Entwicklung ernst meinen, schauen Sie sich in den Internetressourcen die Links zum erweiterten Apex an.

Ressourcen