Apex - Governer Limits

Ausführungsbeschränkungen für Gouverneure stellen die effiziente Nutzung von Ressourcen auf der mandantenfähigen Force.com-Plattform sicher. Dies ist die von Salesforce.com festgelegte Grenze für die Codeausführung für eine effiziente Verarbeitung.

Was sind Governor Limits?

Wie wir wissen, wird Apex in einer Umgebung mit mehreren Mandanten ausgeführt, dh eine einzige Ressource wird von allen Kunden und Organisationen gemeinsam genutzt. Daher muss sichergestellt werden, dass niemand die Ressourcen monopolisiert. Daher hat Salesforce.com die Grenzwerte festgelegt, die die Codeausführung regeln und einschränken. Immer wenn eines der Governor-Limits überschritten wird, wird ein Fehler ausgegeben und die Programmausführung angehalten.

Aus Entwicklersicht ist es wichtig sicherzustellen, dass unser Code skalierbar ist und nicht an die Grenzen stößt.

Alle diese Limits werden pro Transaktion angewendet. Eine einzelne Triggerausführung ist eine Transaktion.

Wie wir gesehen haben, hilft das Trigger-Design-Muster, den Grenzwertfehler zu vermeiden. Wir werden jetzt andere wichtige Grenzen sehen.

Vermeiden von SOQL-Abfragegrenzen

Sie können nur 100 Abfragen pro Transaktion ausgeben. Wenn Ihr Code also mehr als 100 SOQL-Abfragen ausgibt, wird ein Fehler ausgegeben.

Beispiel

Dieses Beispiel zeigt, wie das SOQL-Abfragelimit erreicht werden kann -

Der folgende Auslöser durchläuft eine Kundenliste und aktualisiert die Beschreibung des untergeordneten Datensatzes (Rechnung) mit der Zeichenfolge "Ok to Pay".

// Helper class:Below code needs o be checked.
public class CustomerTriggerHelper {
  
  public static void isAfterUpdateCall(Trigger.new) {
      createInvoiceRecords(trigger.new);//Method call
      updateCustomerDescription(trigger.new);
   }
   
   // Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c> customerList) {
      for (APEX_Customer__c objCustomer: customerList) {
         
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
            
            // condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }
      insert InvoiceList; // DML to insert the Invoice List in SFDC
   }
   
   // Method to update the invoice records
   public static updateCustomerDescription (List<apex_customer__c> customerList) {
      for (APEX_Customer__c objCust: customerList) {
         List<apex_customer__c> invList = [SELECT Id, Name,
            APEX_Description__c FROM APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id];
         
         // This query will fire for the number of records customer list has and will
         // hit the governor limit when records are more than 100
         for (APEX_Invoice__c objInv: invList) {
            objInv.APEX_Description__c = 'OK To Pay';
            update objInv;
            // Update invoice, this will also hit the governor limit for DML if large
            // number(150) of records are there
         }
      }
   }
}

Wenn die Methode 'updateCustomerDescription' aufgerufen wird und die Anzahl der Kundendatensätze mehr als 100 beträgt, wird das SOQL-Limit erreicht. Um dies zu vermeiden, schreiben Sie niemals die SOQL-Abfrage in die For-Schleife. In diesem Fall wurde die SOQL-Abfrage in die For-Schleife geschrieben.

Das folgende Beispiel zeigt, wie Sie sowohl die DML als auch das SOQL-Limit vermeiden können. Wir haben die Abfrage für verschachtelte Beziehungen verwendet, um die Rechnungsdatensätze abzurufen, und die Kontextvariable verwendettrigger.newMap um die Karte mit ID und Kundendatensätzen zu erhalten.

// SOQL-Good Way to Write Query and avoid limit exception
// Helper Class
public class CustomerTriggerHelper {
   public static void isAfterUpdateCall(Trigger.new) {
      createInvoiceRecords(trigger.new);  //Method call
      updateCustomerDescription(trigger.new, trigger.newMap);
   }
   
   // Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c> customerList) {
      for (APEX_Customer__c objCustomer: customerList) {
         
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
            
            // condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }
      insert InvoiceList; // DML to insert the Invoice List in SFDC
   }
   
   // Method to update the invoice records
   public static updateCustomerDescription (List<apex_customer__c>
      customerList, Map<id, apex_customer__c> newMapVariable) {
      List<apex_customer__c> customerListWithInvoice = [SELECT id,
         Name,(SELECT Id, Name, APEX_Description__c FROM APEX_Invoice__r) FROM
         APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];
      
      // Query will be for only one time and fetches all the records
      List<apex_invoice__c> invoiceToUpdate = new
      List<apex_invoice__c>();
      
      for (APEX_Customer__c objCust: customerList) {
         for (APEX_Invoice__c objInv: invList) {
            objInv.APEX_Description__c = 'OK To Pay';
            invoiceToUpdate.add(objInv);
            // Add the modified records to List
         }
      }
      update invoiceToUpdate;
   }
}

DML-Massenanrufe

Dieses Beispiel zeigt den Bulk-Trigger zusammen mit dem Trigger-Helfer-Klassenmuster. Sie müssen zuerst die Hilfsklasse und dann den Trigger speichern.

Note - Fügen Sie den folgenden Code in die zuvor erstellte Klasse 'CustomerTriggerHelper' ein.

// Helper Class
public class CustomerTriggerHelper {
   public static void isAfterUpdateCall(List<apex_customer__c> customerList,
      Map<id, apex_customer__c> mapIdToCustomers, Map<id, apex_customer__c>
      mapOldItToCustomers) {
      createInvoiceRecords(customerList, mapOldItToCustomers);   //Method call
      updateCustomerDescription(customerList,mapIdToCustomers,
      mapOldItToCustomers);
   }
   
   // Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c>
      customerList, Map<id, apex_customer__c> mapOldItToCustomers) {
      List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
      List<apex_customer__c> customerToInvoice = [SELECT id, Name FROM
         APEX_Customer__c LIMIT 1];
      
      for (APEX_Customer__c objCustomer: customerList) {
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            mapOldItToCustomers.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
            //condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            objInvoice.APEX_Customer__c = objCustomer.id;
            InvoiceList.add(objInvoice);
         }
      }
      system.debug('InvoiceList&&&'+InvoiceList);
      insert InvoiceList;
      // DML to insert the Invoice List in SFDC. This also follows the Bulk pattern
   }
   
   // Method to update the invoice records
   public static void updateCustomerDescription (List<apex_customer__c>
      customerList, Map<id, apex_customer__c> newMapVariable, Map<id,
      apex_customer__c> oldCustomerMap) {
      List<apex_customer__c> customerListWithInvoice = [SELECT id,
      Name,(SELECT Id, Name, APEX_Description__c FROM Invoices__r) FROM
         APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];
   
      // Query will be for only one time and fetches all the records
      List<apex_invoice__c> invoiceToUpdate = new List<apex_invoice__c>();
      List<apex_invoice__c> invoiceFetched = new List<apex_invoice__c>();
      invoiceFetched = customerListWithInvoice[0].Invoices__r;
      system.debug('invoiceFetched'+invoiceFetched);
      system.debug('customerListWithInvoice****'+customerListWithInvoice);
   
      for (APEX_Customer__c objCust: customerList) {
         system.debug('objCust.Invoices__r'+objCust.Invoices__r);
         if (objCust.APEX_Active__c == true &&
            oldCustomerMap.get(objCust.id).APEX_Active__c == false) {
            for (APEX_Invoice__c objInv: invoiceFetched) {
               system.debug('I am in For Loop'+objInv);
               objInv.APEX_Description__c = 'OK To Pay';
               invoiceToUpdate.add(objInv);
               // Add the modified records to List
            }
         }
      }
     system.debug('Value of List ***'+invoiceToUpdate);
     update invoiceToUpdate;
      // This statement is Bulk DML which performs the DML on List and avoids
      // the DML Governor limit
   }
}

// Trigger Code for this class: Paste this code in 'Customer_After_Insert'
// trigger on Customer Object
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   CustomerTriggerHelper.isAfterUpdateCall(Trigger.new, trigger.newMap,
      trigger.oldMap);
   // Trigger calls the helper class and does not have any code in Trigger
}

Andere Salesforce Governor-Limits

In der folgenden Tabelle sind die wichtigen Grenzwerte für den Regler aufgeführt.

Beschreibung Grenze
Gesamthaufengröße 6 MB / 12 MB
Gesamtzahl der ausgegebenen DML-Anweisungen 150
Gesamtzahl der Datensätze, die von einer einzelnen SOSL-Abfrage abgerufen wurden 2000
Gesamtzahl der ausgegebenen SOSL-Abfragen 20
Gesamtzahl der von Database.getQueryLocator abgerufenen Datensätze 10000
Gesamtzahl der von SOQL-Abfragen abgerufenen Datensätze 50000