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
Mit Trail Together einem Dozenten folgen
Möchten Sie bei diesem Schritt einem Experten folgen? Schauen Sie sich dieses Video an, das Teil der Reihe "Trail Together" ist.
(Dieser Clip beginnt bei Minute 16:36, für den Fall, dass Sie zurückspringen und den Anfang des Schritts noch einmal sehen möchten.)
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 ein- oder ausgehenden Webservices SOAP oder REST zur Verfügung gestellt wird. |
E-Mail-Services |
Code, der zur Verarbeitung ein- oder ausgehender 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 das leistungsstarke Automatisierungstool Flow Builder, mit dem 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.
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.
- Wählen Sie unter "Setup" Ihr Name > Developer Console aus, um die Entwicklerkonsole zu öffnen.
- Wählen Sie in der Developer Console File > New > Apex Class aus.
- Geben Sie AccountHandler als Klassennamen ein und klicken Sie auf OK.
- 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; } } }
- Drücken Sie Strg + S, um die Klasse zu speichern.
Jetzt, da wir die Handler-Klasse haben, erstellen wir den Account-Auslöser.
- Wählen Sie in der Entwicklerkonsole File > New > Apex Trigger aus.
- Geben Sie als Namen AccountTrigger ein und wählen Sie als sObject Account aus.
- Klicken Sie auf Submit (Senden).
- 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); } }
- 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.
- Wählen Sie unter "Setup" Ihr Name > Developer Console aus, um die Entwicklerkonsole zu öffnen.
- Klicken Sie auf Debug > Open Execute Anonymous Window.
- 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;
- 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.
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.
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 Datensätze 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.
- Wählen Sie unter "Setup" Ihr Name > Developer Console aus, um die Entwicklerkonsole zu öffnen.
- Wählen Sie in der Developer Console File > Open aus.
- Wählen Sie für den Einheitentyp Classes aus. Wählen Sie als Einheit AccountHandler aus.
- Klicken Sie auf Öffnen.
- 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; } } }
- 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.
- Wählen Sie in der Developer Console File > New > Apex Class aus.
- Geben Sie als Klassennamen AccountTrigger_Test ein und klicken Sie auf OK.
- 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()); } }
- Drücken Sie Strg + S, um die Klasse zu speichern.
- Wählen Sie Test > New Run aus.
- Wählen Sie als Testklasse 'AccountTrigger_Test' aus und als Testmethode 'TestCreateNewAccountInBulk'.
- Klicken Sie auf Ausführen.
- Wählen Sie die Registerkarte Tests 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.
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
-
Invoking Apex im Apex Code Developer’s Guide
-
Erste Schritte mit Apex-Auslösern im Trail "Entwickler – Anfänger"
-
Executing Governors and Limits
-
Testen von Apex-Auslösern im Trail "Entwickler – Anfänger"