Skip to main content

Anwenden der Prinzipien der Selector-Schicht in Apex

Lernziele

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

  • Erstellen einer Apex-Selektor-Klasse und effektives Nutzen dieser Klasse
  • Sicherstellen, dass Felder einheitlich abgefragt werden
  • Implementieren von Unterauswahl- und objektübergreifenden Abfragen mit dem Selektor-Muster
  • Dynamisches Abfragen von Felder aus einem FieldSet, zusätzlich zu Ihrem eigenen
  • Steuern, wann Sicherheitsmaßnahmen der Plattform durchgesetzt werden
Hinweis

Hinweis

Lernen Sie auf Deutsch? In diesem Badge ist für die praktischen Trailhead-Aufgaben Englisch als Bearbeitungssprache festgelegt. Übersetzungen werden zur Referenz in Klammern angegeben. Vergewissern Sie sich, dass Sie in Ihrem Trailhead-Playground (1) das Gebietsschema auf USA und (2) die Sprache auf Englisch festgelegt haben. (3) Verwenden Sie zum Kopieren und Einfügen nur die englischen Werte. Die zugehörigen Anweisungen finden Sie hier.

Weitere Details dazu, wie Sie die übersetzte Trailhead-Umgebung optimal nutzen können, finden Sie unter dem Badge "Trailhead in Ihrer Sprache".

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 55:16, für den Fall, dass Sie zurückspringen und den Anfang des Schritts noch einmal sehen möchten.)

Implementieren einer Selektor-Klasse

Zum Abschluss dieses Moduls tauchen wir tief in die Selektor-Klasse und ihre Implementierung ein. Diese Selektor-Implementierung verwendet die Basisklasse fflib_SObjectSelector, um die Erstellung und Ausführung von SOQL-Abfragen einfacher, konsistenter und kompatibler zu machen, da weniger Bausteincode vom Entwickler geschrieben wird. Dies geschieht dynamisch, wobei dennoch sichergestellt wird, dass die Kompilierungs- und Referenzintegrität der angefragten Felder aufrechterhalten wird. Außerdem stellt die Implementierung nützliche allgemeine Abfragefunktionen zur Verfügung.

  • Funktion zum Einschluss der Organisation": abhängige Felder, wie etwa das Feld CurrencyIsoCode, die nur sichtbar sind, wenn die Funktion für mehrere Währungen aktiviert ist.
  • Möglichkeit, (optional) Felder einzuschließen, die vom Administrator über ein FieldSet definiert werden
  • Durchsetzen von Plattformsicherheit durch Auslösen einer Ausnahme, wenn der Benutzer keinen Lesezugriff auf das Objekt besitzt. Sie können diese Funktion über ein Konstruktorargument deaktivieren, wenn der aufrufende Code sie umgehen möchte, da der Objektzugriff indirekt für einen Vorgang erfolgt, den der Benutzer durchführt.

Die folgende Abbildung zeigt die Methoden der Basisklasse fflib_SObjectSelector. Da dies eine abstrakte Basisklasse ist, müssen Sie mindestens die als abstrakt gekennzeichneten Methoden implementieren, bevor Sie die Klasse erweitern können.

Methoden in der fflibSObjectSelector-Basisklasse

Folgende abstrakte Methoden müssen implementiert werden:

  • Abstrakte Methode Schema.SObjectType getSObjectType();
  • Abstrakte Methode List<Schema.SObjectField> getSObjectFieldList();

Der folgende Code ist ein einfaches Beispiel für eine Selektor-Klasse für das Objekt Product2. Obwohl die selectSObjectsById()-Methode direkt von der Basisklasse aus aufgerufen werden kann, wird in der Regel die selectById()-Methode implementiert, um klar zu machen, dass sie eine Liste mit Product2-Datensätzen zurückgibt.

public class ProductsSelector extends fflib_SObjectSelector {
    public List<Schema.SObjectField> getSObjectFieldList() {
        return new List<Schema.SObjectField> {
            Product2.Description,
            Product2.Id,
            Product2.IsActive,
            Product2.Name,
            Product2.ProductCode,
            Product2.DiscountingApproved__c};
    }
    public Schema.SObjectType getSObjectType() {
        return Product2.sObjectType;
    }
    public List<Product2> selectById(Set<ID> idSet) {
        return (List<Product2>) selectSObjectsById(idSet);
    }
}

Bei diesem Beispiel wird beim Aufruf der selectById()-Methode die folgende SOQL erzeugt und ausgeführt. Wie Sie sehen, wurde auch etwas allgemeines Basisklassenverhalten in die SOQL eingefügt, um eine einheitliche Reihenfolge zu erreichen. Bei diesem Beispiel wird standardmäßig nach dem Feld "Name" sortiert, da noch keine Alternative angegeben wurde.

SELECT Description, Id, IsActive, Name, ProductCode
  FROM Product2
  WHERE id in :idSet
  ORDER BY Name ASC NULLS FIRST

Durch die Implementierung der getSObjectFieldList()-Methode wurde eine Liste mit Feldern definiert, die die Basisklasse in der selectSObjectsById()-Methode abfragen soll, wobei sichergestellt wird, dass der abgefragte Datensatz die Basisfelder enthält und diese immer einheitlich ausgefüllt sind. Dies beugt möglichen Problemen mit inkonsistent ausgefüllten Datensätzen vor, die zu weniger robusten Codeausführungspfaden führen können.

Expertentipp: Hier muss zwischen der Apex Heap-Größe und der Häufigkeit abgewogen werden, mit der Felder von verschiedenen Aufrufern der Selektor-Methoden benötigt werden. Es wird empfohlen, nur eine kleine Menge von Feldern einzuschließen, die für den Großteil Ihrer Logik in den meisten Fällen sinnvoll ist. Lassen Sie selten verwendete, große Textfelder oder Rich-Text-Felder weg und stellen Sie sie stattdessen mit dedizierten Methoden bereit, die Listen mit benutzerdefinierten Apex-Typen zurückgeben, wie dies später in dieser Einheit beschrieben wird.

Sie können auch die getOrderBy()-Methode überschreiben, um sicherzustellen, dass alle von der Basisklasse erstellten oder ausgeführten Abfragen dieselben Sortierkriterien verwenden, wie dies im folgenden Beispiel gezeigt wird.

public override String getOrderBy() {
    return 'IsActive DESC, ProductCode';
}

Wird die oben angegebene Methode überschrieben, sieht die von selectById() erzeugte SOQL jetzt so aus:

SELECT Description, Id, IsActive, Name, ProductCode,
  FROM Product2
  WHERE id in :idSet
  ORDER BY IsActive DESC NULLS FIRST , ProductCode ASC NULLS FIRST

Implementieren benutzerdefinierter Selektor-Methoden

Bisher haben wir die abstrakten Methoden in der Basisklasse implementiert und uns angesehen, wie sich dies auf die Abfrage auswirkt, die beim Aufrufen der selectById()-Methode der Basisklasse erzeugt wird. Jetzt fügen wir einige Selektor-Klassenmethoden hinzu, die verschiedene Abfragen ausführen können, um die Kriterien, die ausgewählten Felder und andere Aspekte der notwendigen Abfragen zu variieren.

Wenn Sie eine benutzerdefinierte Selektor-Methode implementieren und dennoch die Konsistenz der Felder und die vom Selektor vorgegebene Reihenfolge wahren möchten, können Sie die bereits implementierten, oben aufgeführten Methoden aufrufen. Es folgt ein einfaches Beispiel für dynamische SOQL, das zeigt, wie Sie dies mit einem einfachen String-Format bewerkstelligen.

public List<Opportunity> selectRecentlyUpdated(Integer recordLimit) {
    String query = String.format(
    'select {0} from {1} ' +
    'where SystemModstamp = LAST_N_DAYS:30 ' +
    'order by {2} limit {3}',
    new List<String> {
        getFieldListString(),
        getSObjectName(),
        getOrderBy(),
        String.valueOf(recordLimit)
      }
    );
    return (List<Opportunity>) Database.query(query);
}

Factory-Abfrageansatz für die Erstellung von SOQL-Abfragen

Der obige Ansatz zur Abfrageerstellung mit dem String-Format (String.format) funktioniert, wird mit zunehmender Komplexität der Abfragen jedoch schwerer zu lesen und zu pflegen.

Die Basisklasse fflib_SObjectSelector bietet auch eine eher objektorientierte Methode zur Abfrageerstellung mithilfe eines Builder-Musteransatzes, der von der fflib_QueryFactory-Klasse bereitgestellt wird. Diese Klasse hat den Zweck, die dynamische Erstellung von SOQL-Anweisungen robuster und weniger fehleranfällig als herkömmliche String-Verkettungsansätze zu machen. Ihre Methodensignaturen folgen dem Design-Modell "Fluent Interface".

Sie können eine eigene Instanz der fflib_QueryFactory-Klasse erstellen und ihre Methoden aufrufen, um anzugeben, welches Objekt und welche Felder Sie abfragen möchten. Die Selektor-Basisklasse stellt dafür jedoch die Hilfsmethode newQueryFactory()zur Verfügung, die die oben implementierten Methoden nutzt. Sie können diese Instanz dann, wie unten gezeigt mit Kriterien (WHERE-Klauseln) anpassen, bevor Sie anfordern, dass die Abfrage durch die Factory mittels der toSOQL()-Methode erstellt und dann auf herkömmliche Weise ausgeführt wird.

public List<Product2> selectRecentlyUpdated(Integer recordLimit) {   
    return (List<Product2>) Database.query(
        //  Query factory has been pre-initialised by calling
        //  getSObjectFieldList(), getOrderBy() for you.        newQueryFactory()
        //  Now focus on building the remainder of the
        //  query needed for this method using the setCondition() method
        .setCondition('SystemModstamp = LAST_N_DAYS:30').

        //  set the number of records to limit the query to 
       .setLimit(recordLimit)

        // Finally build the query to execute
        .toSOQL()
    );
}

Wird die benutzerdefinierte Selektor-Methode mit dem Parameter 10 aufgerufen, wird die folgende SOQL ausgeführt.

SELECT Description, Id, IsActive, Name, ProductCode,
  FROM Product2
  WHERE SystemModstamp = LAST_N_DAYS:30
  ORDER BY IsActive DESC NULLS FIRST, ProductCode ASC NULLS FIRST
  LIMIT 10

Feldteilmengenauswahl und objektübergreifende Abfragen

Im nächsten Beispiel wird der Parameter "false" an die newQueryFactory()-Methode übergeben, um die Basisklasse anzuweisen, die in getSObjectFieldList() angegebenen Felder beim Erstellen der Factory-Abfrageinstanz zu ignorieren. Anschließend verwenden wir die selectField()-Methode, um spezifische Felder aus dem "Opportunity"-Objekt und, in diesem Fall aus den die zugehörigen Account- und Benutzerobjekten hinzuzufügen, um eine objektübergreifende Abfrage zu erstellen. Da das Basis-SObject der Abfrage die Opportunity ist, befindet sich diese Methode in diesem Fall in der OpportunitiesSelector-Klasse.

Ein weiterer Unterschied im folgenden Beispiel besteht darin, dass es keine List<Opportunity> mit nur spezifischen, ausgefüllten Feldern zurückgibt und vom Aufrufer erwartet zu wissen, was ausgefüllt wurde. Vielmehr umgibt die Methode jeden Datensatz mit einer kleinen Apex-Klasse namens OpportunityInfo, um explizit nur die abgefragten Feldwerte verfügbar zu machen. Dies ist ein viel sicherer, selbstdokumentierender und engerer Vertrag mit dem Aufrufer der Selektor-Methode.

public List<OpportunityInfo> selectOpportunityInfo(Set<Id> idSet) {
    List<OpportunityInfo> opportunityInfos = new List<OpportunityInfo>();
    for(Opportunity opportunity :Database.query(
            newQueryFactory(false)
                .selectField(Opportunity.Id)
                .selectField(Opportunity.Amount)
                .selectField(Opportunity.StageName)
                .selectField('Account.Name')
                .selectField('Account.AccountNumber')
                .selectField('Account.Owner.Name')
                .setCondition('id in :idSet')
                .toSOQL()))
    {
        opportunityInfos.add(new OpportunityInfo(opportunity));
    }
    return opportunityInfos;
}
public class OpportunityInfo 
{       
    private Opportunity opportunity;
    public OpportunityInfo(Opportunity opportunity) {this.opportunity = opportunity; }
    public Id Id { get { return this.opportunity.Id; } }     
    public Decimal Amount { get { return this.opportunity.Amount; } }        
    public String Stage { get { return this.opportunity.StageName; } }       
    public String AccountName { get { return this.opportunity.Account.Name; } }      
    public String AccountNumber { get { return this.opportunity.Account.AccountNumber; } }       
    public String AccountOwner { get { return opportunity.Account.Owner.Name; } }         
}

Expertentipp: Sie sollten diese Möglichkeit auch in Betracht ziehen, wenn Sie AggregateDatabaseResult verwenden, um eine Apex-Klasse zurückzugeben, die mehr auf die in diesen Ergebnistypen enthaltenen Informationen zugeschnitten ist. Vermeiden Sie bei diesem Ansatz die übermäßige Verbreitung von inneren Klassen. Die standardmäßige Feldauswahl des Selektors umfasst wirklich die Felder, von denen Sie erwarten, sie am häufigsten zu verwenden, und daher gibt diese Auswahl konkrete sObjects zurück. Sie sollten diese Klassen eventuell auch zwischen Methoden wiederverwenden.

Der obige Code erzeugt die folgende SOQL-Anweisung:

SELECT Id, StageName, Amount, Account.AccountNumber, Account.Name, Account.Owner.Name
  FROM Opportunity WHERE id in :idSet
  ORDER BY Name ASC NULLS FIRST

FieldSet-Unterstützung

Eine weitere Funktion der fflib_SObjectSelector-Basisklasse ist die Einbeziehung von Feldern, auf die von einem bestimmten FieldSet verwiesen wird. Dies macht den Selektor halb-dynamisch und ermöglicht Ihnen, die Ergebnisse zusammen mit einer Lightning-Webseite oder einer Visualforce-Seite zu verwenden, die erfordert, dass die Felder abgefragt wurden. Das folgende Beispiel, wie dies mittels eines Konstruktorparameters gelingt, der zum Steuern des standardmäßigen Einschlusses von Fieldset-Feldern dient. Sie müssen zudem die getSObjectFieldSetList()-Methode überschreiben. Der Rest des Selektors bleibt gleich.

public class ProductSelector extends fflib_SObjectSelector {
    public ProductsSelector() {
        super(false);
    }
    public ProductsSelector(Boolean includeFieldSetFields) {
        super(includeFieldSetFields);
    }
    public override List<Schema.FieldSet> getSObjectFieldSetList() {
        return new List<Schema.FieldSet>
                { SObjectType.Product2.FieldSets.MyFieldSet };
    }
    // Reminder of the Selector methods are the same
    // ...}

Es folgt ein kurzes Beispiel zur Verwendung dieses neuen Fieldset-Konstruktorparameters. Obwohl der Beispielcode davon ausgeht, dass das Feld MyText__c existiert und zum FieldSet hinzugefügt wurde, muss erst der Parameter "true" an seinen Konstruktor übergeben werden, damit die Basisklasse dynamisch Felder einfügt, die der Administrator zu MyFieldSet hinzugefügt hat.

// Test data
Product2 product = new Product2();
product.Description = 'Something cool';
product.Name = 'CoolItem';
product.IsActive = true;
product.MyText__c = 'My Text Field';
insert product;                 
// Query (including FieldSet fields)
List<Product2> products =
  new ProductsSelector(true).selectById(new Set<Id> { product.Id });
// Assert (FieldSet has been pre-configured to include MyText__c here)
System.assertEquals('Something cool', products[0].Description);    
System.assertEquals('CoolItem', products[0].Name);     
System.assertEquals(true, products[0].IsActive);       
System.assertEquals('My Text Field', products[0].MyText__c);

Verwenden spezifischer FieldSets in benutzerdefinierten Selektor-Methoden

Eventuell gibt es mehrere FieldSets zu Ihrem Objekt, und Sie möchten nicht, dass alle Selektor-Methoden die FieldSets auf der Ebene der Selektor-Klasse verwenden. Sie können festlegen, dass die Fieldsets als Parameter an Ihre Selektor-Methoden übergeben und nicht registriert werden (siehe dieses Beispiel).

public List<Product2> selectById(Set<ID> idSet, Schema.FieldSet fieldSet) {
  return (List<Product2>) Database.query(
    newQueryFactory()
      .selectFieldSet(fieldSet)
      .setCondition('id in :idSet')
      .toSOQL()
  );
}

Fortgeschritten: Wiederverwenden von Feldlisten für objektübergreifende und Unterauswahlabfragen

Sie können auch Instanzen von Selektor-Klassen erstellen, die untergeordnete Objekte darstellen, wenn Sie benutzerdefinierte Selektor-Methoden implementieren, die objektübergreifende Feld- und Unterauswahlabfragen verwenden.

Durch die Verwendung untergeordneter Selektoren in diesem Prozess wird sichergestellt, dass Sie auch die für diese Objekte definierten Selektor-Felder nutzen, selbst wenn diese Datensätze innerhalb einer Unterauswahl- oder objektübergreifenden Abfrage abgefragt werden.

Im folgenden Beispiel werden die Basisklassenmethoden addQueryFactorySubselect() und configureQueryFactoryFields() verwendet. Durch das Erstellen von Instanzen der Selektoren für untergeordnete Objekte fügen diese Methoden die Selektor-Felder in die Factory-Abfrageinstanz ein, die von der benutzerdefinierten Selektor-Methode für das übergeordnete Objekt bereitgestellt wird, die die Abfrage im Endeffekt ausführt.

Um eine Unterauswahl zu Ihrer Basisabfrage hinzuzufügen, beginnen Sie mit der Abfrage-Factory für das Basis-SObject. Dann instanziieren Sie die Abfrage-Factory für das SObject, das Teil der Unterauswahl ist. Sie rufen die addQueryFactorySubselect()-Methode für die Abfrage-Factory des Unterauswahl-SObjects auf und übergeben die Abfrage-Factory des Basis-SObjects als Parameter. Wenn Sie die toSOQL()-Methode für die Abfrage-Factory des Basis-SObjects ausführen, wird die Unterauswahlabfrage hinzugefügt.

Um ein SObject über eine Beziehungsabfrage für ein Feld mit dem Datentyp "Nachschlagen" oder "Master-Detail" hinzuzufügen, beginnen Sie mit der Abfrage-Factory für das Basis-SObject. Dann instanziieren Sie die Abfrage-Factory für das übergeordnete SObject, dessen Felder zur Basisabfrage hinzugefügt werden. Danach rufen Sie die configureQueryFactoryFields()-Methode für die Abfrage-Factory des übergeordneten SObjects auf und übergeben die Abfrage-Factory des Basis-SObjects und den API-Namen der Beziehung des übergeordneten Felds als Parameter. Wenn Sie die toSOQL()-Methode für die Abfrage-Factory des Basis-SObjects ausführen, werden die Felder des übergeordneten SObjects unter Verwendung des als Parameter angegebenen Beziehungsnamens zum SELECT-Teil der Basisabfrage hinzugefügt.

Im folgenden Beispiel werden sowohl Opportunities, untergeordnete Opportunity-Produkte und zugehörige Informationen aus den Objekten "Project" und "Pricebook" abgefragt, wobei die entsprechenden untergeordneten Selektor-Klassen wiederverwendet werden.

public List<Opportunity> selectByIdWithProducts(Set<ID> idSet) {
    // Query Factory for this Selector (Opportunity)
    fflib_QueryFactory opportunitiesQueryFactory = newQueryFactory();
    // Add a query sub-select via the Query Factory for the Opportunity Products
    fflib_QueryFactory lineItemsQueryFactory =
        new OpportunityLineItemsSelector().            addQueryFactorySubselect(opportunitiesQueryFactory);
    // Add cross object query fields for Pricebook Entry, Products and Pricebook
    new PricebookEntriesSelector().        configureQueryFactoryFields(lineItemsQueryFactory, 'PricebookEntry');
    new ProductsSelector().        configureQueryFactoryFields(lineItemsQueryFactory, 'PricebookEntry.Product2');
    new PricebooksSelector().        configureQueryFactoryFields(lineItemsQueryFactory, 'PricebookEntry.Pricebook2');
    // Set the condition and build the query
    return (List<Opportunity>) Database.query(
        opportunitiesQueryFactory.setCondition('id in :idSet').toSOQL());
}

Daraus ergibt sich die folgende SOQL-Abfrage. Beachten Sie, dass sogar die Unterauswahl die Standardreihenfolge wiederverwendet, die von OpportunityLineItemsSelector festgelegt wird (in den Beispielen dieser Einheit nicht zu sehen).

SELECT
  AccountId, Amount, CloseDate, Description,
  DiscountType__c, ExpectedRevenue, Id, Name,
  Pricebook2Id, Probability, StageName, Type,  
  (SELECT
      Description, Id, ListPrice, OpportunityId,
      PricebookEntryId, Quantity, SortOrder,
      TotalPrice, UnitPrice, PricebookEntry.Id,
      PricebookEntry.IsActive, PricebookEntry.Name,
      PricebookEntry.Pricebook2Id, PricebookEntry.Product2Id,
      PricebookEntry.ProductCode, PricebookEntry.UnitPrice,
      PricebookEntry.UseStandardPrice,
      PricebookEntry.Pricebook2.Description,
      PricebookEntry.Pricebook2.Id,
      PricebookEntry.Pricebook2.IsActive,
      PricebookEntry.Pricebook2.IsStandard,
      PricebookEntry.Pricebook2.Name,
      PricebookEntry.Product2.Description,
      PricebookEntry.Product2.Id,
      PricebookEntry.Product2.IsActive,
      PricebookEntry.Product2.Name,
      PricebookEntry.Product2.ProductCode
     FROM OpportunityLineItems
     ORDER BY SortOrder ASC NULLS FIRST, PricebookEntry.Name ASC NULLS FIRST)
FROM Opportunity WHERE id in :idSet
ORDER BY Name ASC NULLS FIRST

Steuern der Durchsetzung von Objekt- und Feldebenensicherheit

Standardmäßig setzt die Basisklasse fflib_SObjectSelector Salesforce-Objektsicherheit durch, indem sie eine Ausnahme auslöst, wenn der ausführende Benutzer keinen Lesezugriff auf das Objekt besitzt. Die Klasse setzt die Feldebenensicherheit jedoch nicht standardmäßig durch, es sei denn, dies wurde explizit aktiviert, wie in diesem Abschnitt beschrieben wird.

Aufgrund ähnlicher Logik in der Basisklasse der Domain-Schicht, die in einer früheren Einheit beschrieben wurde, gilt diese Durchsetzung für alle Arten von Zugriff auf das Objekt, ob durch ein Steuerfeld, einen Service oder eine Domain. Intern kann Service- oder Domain-Logik im Namen eines Benutzers auf ein Objekt zuzugreifen versuchen, der nicht die erforderliche Berechtigung besitzt.

Wenn Sie diese standardmäßige Sicherheitsdurchsetzung durch die Basisklasse jedoch lieber deaktivieren und selbst implementieren möchten, können Sie Konfigurationsparameter im Konstruktor der Basisklasse verwenden. Das folgende Beispiel zeigt, wie Sie dies im Konstruktor jeder Selektor-Klasse realisieren. Sie können eine eigene Basisklasse erstellen und sie dann auf alle Selektor-Klassen erweitern, um zusätzlichen Bausteincode zu vermeiden und nach eigenen Anwendungsregeln zu standardisieren.

public PricebookEntriesSelector() {
    super(false, // Do not include FieldSet fields
          false, // Do not enforce Object level security
          false); // Do not enforce Field level security
}

Wenn Sie möchten, dass der Aufrufer die Durchsetzung übernimmt, sollten Sie überlegen, einen überladenen Konstruktor wie den folgenden hinzuzufügen. So kann der Standardkonstruktor standardmäßig auf "keine Sicherheit" festgelegt werden und von Aufrufern gefordert werden, dass sie den anderen Konstruktor verwenden, um zu fordern, dass die Durchsetzung nach Bedarf aktiviert wird.

public PricebookEntriesSelector(Boolean enforceObjectAndFieldSecurity) {
    super(false, // Do not include FieldSet fields
      enforceObjectAndFieldSecurity, enforceObjectAndFieldSecurity);
}

Steuern der Sicherheitsdurchsetzung von Freigaberegeln

Eine andere Form der Sicherheitsdurchsetzung, die Selektor-Methoden in Betracht ziehen müssen, ist die Frage, ob Freigaberegeln angewandt wurden. Gemäß den Designüberlegungen für die Service-Schicht bzw. Visualforce- oder Lightning-Steuerfeldklassen ist das Schlüsselwort with sharing eine bewährte Vorgehensweise. Jeder Code in diesen Klassen, der eine Selektor-Methode aufruft, wird ebenfalls in diesem Kontext ausgeführt. Wenn diese Konventionen eingehalten werden, werden bei der Ausführung des Selektor-Codes with sharing (Freigaberegeln) standardmäßig angewandt.

Wie die Filterkriterien in der WHERE-Klausel bei der Abfrageausführung, wirkt sich auch das Schlüsselwort "sharing" auf das ausgewählte Datensatzset aus. Wenn Sie eine Anforderung zur Auswahl aller Datensätze unabhängig von Freigaberegeln kapseln möchten, können Sie einem Muster aus einer expliziten (Methodenname) und internen Erweiterung folgen, indem Sie eine private innere Klasse mit dem erforderlichen Schlüsselwort without sharing als Anmerkung verwenden. Bei diesem Ansatz wird diese Anforderung gekapselt und vermieden, dass der Aufrufer diese Anforderung ausdrücken muss, indem er künstlich eine Klasse für den Aufruf dieses Verhaltens erstellt.

public class OpportunitiesSelector extends fflib_SObjectSelector {
    public List<Opportunity> selectById(Set<Id> idSet) {
        // This method simply runs in the sharing context of the caller
        // ...        return opportunities;
    }
    public List<OpportunityInfo> selectOpportunityInfoAsSystem(Set<Id> idSet) {
        // Explicitly run the query in a 'without sharing' context
        return new SelectOpportunityInfo().selectOpportunityInfo(this, idSet);
    }
    private without sharing class SelectOpportunityInfo {
        public List<OpportunitiesSelector.OpportunityInfo> selectOpportunityInfo(OpportunitiesSelector selector, Set<Id> idSet) {
            // Execute the query as normal
            // ...           return opportunityInfos;             
        }
    }
}

Ressourcen

Lernen Sie weiter kostenlos!
Registrieren Sie sich für einen Account, um fortzufahren.
Was ist für Sie drin?
  • Holen Sie sich personalisierte Empfehlungen für Ihre Karriereplanung
  • Erproben Sie Ihre Fähigkeiten mithilfe praktischer Aufgaben und Quizze
  • Verfolgen Sie Ihre Fortschritte nach und teilen Sie sie mit Arbeitgebern
  • Nutzen Sie Mentoren und Karrierechancen