Bearbeiten von Datensätzen mit DML
Lernziele
Nachdem Sie diese Lektion abgeschlossen haben, sind Sie in der Lage, die folgenden Aufgaben auszuführen:
- Einfügen, Aktualisieren und Löschen von Datensätzen mithilfe von DML
- Ausführen von DML-Anweisungen als Massenvorgang
- Einfügen oder Aktualisieren eines Datensatzes mithilfe von "upsert"
- Abfangen einer DML-Ausnahme
- Einfügen neuer Datensätze mit der Option für Teilerfolg und Verarbeiten der Ergebnisse mithilfe einer "Database"-Methode
- Wissen, wann DML-Anweisungen und wann "Database"-Methoden zu verwenden sind
- Durchführen von DML-Vorgängen in verknüpften Datensätzen
Bearbeiten von Datensätzen mit DML
Erstellen und bearbeiten Sie Datensätze in Salesforce mithilfe der Datenmanipulationssprache (Data Manipulation Language, DML). DML stellt einfache Anweisungen zum Einfügen, Aktualisieren, Zusammenführen, Löschen und Wiederherstellen von Datensätzen bereit und bietet damit eine unkomplizierte Möglichkeit zur Verwaltung von Datensätzen.
Da Apex eine datenorientierte Sprache ist und auf der Lightning Platform gespeichert wird, hat es direkten Zugriff auf Ihre Daten in Salesforce. Im Gegensatz zu anderen Programmiersprachen, die zusätzliche Einrichtung erfordern, um sich mit Datenquellen zu verbinden, ist die Verwaltung von Datensätzen mit Apex DML ein Kinderspiel. Durch Aufrufen von DML-Anweisungen können Sie im Handumdrehen Vorgänge in Ihren Salesforce-Datensätzen ausführen. In diesem Beispiel wird der Account "Acme" in Salesforce hinzugefügt. Zuerst wird sObject für den Account erstellt und dann als Argument an die insert-Anweisung übergeben, die den Datensatz in Salesforce persistent ablegt.
// Create the account sObject Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100); // Insert the account by using DML insert acct;
DML-Anweisungen
Die folgenden DML-Anweisungen stehen zur Verfügung.
insert
update
upsert
delete
undelete
merge
Jede DML-Anweisung akzeptiert entweder ein einzelnes sObject oder eine Liste (bzw. ein Array) von sObjects. Mithilfe einer Liste von sObjects lassen sich Datensätze wesentlich effizienter verarbeiten.
Mit Ausnahme von zwei Anweisungen handelt es sich bei allen diesen Anweisungen um vertraute Datenbankvorgänge. Die Anweisungen upsert
und merge
sind Salesforce-spezifische Anweisungen und können sehr praktisch sein.
Mit dem DML-Vorgang upsert
werden in einer einzigen Anweisung neue Datensätze erstellt und sObject-Datensätze aktualisiert. Dabei wird anhand eines angegebenen Felds oder, wenn kein Feld angegeben wird, anhand des ID-Felds ermittelt, ob es bereits vorhandene Objekte gibt.
Die Anweisung merge
führt bis zu drei Datensätze desselben sObject-Typs in einem der Datensätze zusammen. Dabei werden die anderen Datensätze gelöscht und alle zugehörigen Datensätze neu zugeordnet.
ID-Feld wird automatisch neuen Datensätzen zugewiesen
Beim Einfügen von Datensätzen weist das System jedem Datensatz eine ID zu. Der ID-Wert wird einerseits persistent in der Datenbank abgelegt und andererseits automatisch in der sObject-Variablen eingetragen, die Sie im DML-Aufruf als Argument verwendet haben.
Das folgende Beispiel zeigt, wie die ID für das sObject abgerufen wird, das dem eingefügten Account entspricht.
// Create the account sObject Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100); // Insert the account by using DML insert acct; // Get the new ID on the inserted sObject argument ID acctID = acct.Id; // Display this ID in the debug log System.debug('ID = ' + acctID); // Debug log result (the ID will be different in your case) // DEBUG|ID = 001D000000JmKkeIAF
DML-Massenvorgänge
Sie können DML-Vorgänge entweder für ein einzelnes sObject oder als Massenvorgang für eine Liste von sObjects ausführen. DML-Massenvorgänge werden empfohlen, da dadurch das Überschreiten zulässiger Obergrenzen vermieden wird, z. B. die DML-Obergrenze von 150 Anweisungen pro Apex-Transaktion. Diese Obergrenze wurde etabliert, um fairen Zugriff auf gemeinsam genutzte Ressourcen auf der Lightning Platform sicherzustellen. Die Ausführung eines DML-Vorgangs für eine Liste von sObjects wird als eine DML-Anweisung gezählt und nicht als eine Anweisung für jedes sObject.
Im folgenden Beispiel werden Kontakte als Massenvorgang eingefügt, indem in einem Aufruf eine Liste von Kontakten eingefügt wird. Anschließend werden diese Kontakte ebenfalls als Massenvorgang aktualisiert.
- Führen Sie diesen Codeauszug mit anonymem Apex-Code in der Entwicklerkonsole aus.
// Create a list of contacts List<Contact> conList = new List<Contact> { new Contact(FirstName='Joe',LastName='Smith',Department='Finance'), new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'), new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'), new Contact(FirstName='Kim',LastName='Shain',Department='Education')}; // Bulk insert all contacts with one DML call insert conList; // List to hold the new contacts to update List<Contact> listToUpdate = new List<Contact>(); // Iterate through the list and add a title only // if the department is Finance for(Contact con : conList) { if (con.Department == 'Finance') { con.Title = 'Financial analyst'; // Add updated contact sObject to the list. listToUpdate.add(con); } } // Bulk update all contacts with one DML call update listToUpdate;
- Überprüfen Sie die eben erstellten Kontakte in Ihrer Organisation.
Bei zwei Kontakten aus der Finanzabteilung sollte die Stellenbezeichnung mitFinancial analyst
ausgefüllt worden sein.
Gleichzeitiges Aktualisieren/Einfügen von Datensätzen
Wenn Sie über eine Liste mit sowohl neuen als auch bereits vorhandenen Datensätzen verfügen, können Sie Einfügungen und Aktualisierungen an allen Datensätzen in der Liste mithilfe der Anweisung upsert
verarbeiten. Mit "upsert" wird die Erstellung doppelter Datensätze vermieden und Sie können Zeit sparen, da Sie nicht ermitteln müssen, welche Datensätze zuerst vorhanden waren.
Die Anweisung upsert
gleicht die sObjects mit vorhandenen Datensätzen ab, indem die Werte eines Felds verglichen werden. Wenn Sie beim Aufrufen dieser Anweisung kein Feld angeben, verwendet die Anweisung upsert
für den Abgleich des sObject mit vorhandenen Datensätzen in Salesforce die ID des sObject. Alternativ können Sie ein Feld für den Abgleich angeben. Geben Sie für benutzerdefinierte Objekte ein benutzerdefiniertes Feld an, das als externe ID gekennzeichnet ist. Für Standardobjekte können Sie jedes Feld angeben, bei dem die Eigenschaft "idLookup" auf "true" (wahr) festgelegt ist. Beim E-Mail-Feld eines Kontakts oder Benutzers beispielsweise ist die Eigenschaft "idLookup" festgelegt. Informationen zum Überprüfen der Eigenschaft eines Felds finden Sie im Handbuch Object Reference for Salesforce and Lightning Platform.
Syntax für "upsert"
upsert sObject | sObject[] upsert sObject | sObject[] field
Bei dem optionalen Feld handelt es sich um ein Feld-Token. Zur Angabe des Felds "MyExternalID" lautet die Anweisung beispielsweise:
upsert sObjectList Account.Fields.MyExternalId;
"upsert" verwendet den Primärschlüssel (die ID) des sObject-Datensatzes, ein "idLookup"-Feld oder ein Feld für eine externe ID, um zu ermitteln, ob ein neuer Datensatz erstellt oder ein vorhandener aktualisiert werden soll:
- Wird für den Schlüssel keine Übereinstimmung gefunden, wird ein neuer Objektdatensatz erstellt.
- Wird für den Schlüssel eine Übereinstimmung gefunden, wird der vorhandene Objektdatensatz aktualisiert.
- Werden für den Schlüssel mehrere Übereinstimmungen gefunden, wird ein Fehler ausgegeben und der Objektdatensatz wird weder eingefügt noch aktualisiert.
Dieses Beispiel zeigt, wie mit "upsert" in einem Aufruf ein vorhandener Kontaktdatensatz aktualisiert und ein neuer Kontakt eingefügt wird. Dieser upsert-Aufruf aktualisiert den vorhandenen Kontakt "John" und fügt einen neuen Kontakt, "Kathy", ein.
- Führen Sie diesen Codeauszug im Fenster für die anonyme Ausführung der Entwicklerkonsole aus.
// Insert the Josh contact Contact josh = new Contact(FirstName='Josh',LastName='Kaplan',Department='Finance'); insert josh; // Josh's record has been inserted // so the variable josh has now an ID // which will be used to match the records by upsert josh.Description = 'Josh\'s record has been updated by the upsert operation.'; // Create the Kathy contact, but don't persist it in the database Contact kathy = new Contact(FirstName='Kathy',LastName='Brown',Department='Technology'); // List to hold the new contacts to upsert List<Contact> contacts = new List<Contact> { josh, kathy }; // Call upsert upsert contacts; // Result: Josh is updated and Kathy is created.
- Überprüfen Sie alle Kontakte in Ihrer Organisation.
Ihre Organisation verfügt über nur einen "Josh Kaplan"-Datensatz, nicht zwei, da der "upsert"-Vorgang den vorhandenen Datensatz gefunden und ihn aktualisiert hat, statt einen neuen Kontaktdatensatz zu erstellen. Es gibt auch einen "Kathy Brown"-Kontaktdatensatz.
Alternativ können Sie ein Feld für den Abgleich der Datensätze angeben. Im folgenden Beispiel wird das E-Mail-Feld für den Kontakt verwendet, da bei diesem die Eigenschaft "idLookup" festgelegt ist. Bei diesem Beispiel wird der Kontakt "Jane Smith" eingefügt sowie ein zweites Kontakt-sObject erstellt und mit derselben E-Mail-Adresse ausgefüllt. Anschließend wird "upsert
" aufgerufen, um den Kontakt unter Verwendung des E-Mail-Felds für den Abgleich zu aktualisieren.
- Führen Sie diesen Codeauszug im Fenster für die anonyme Ausführung der Entwicklerkonsole aus.
Contact jane = new Contact(FirstName='Jane', LastName='Smith', Email='jane.smith@example.com', Description='Contact of the day'); insert jane; // 1. Upsert using an idLookup field // Create a second sObject variable. // This variable doesn’t have any ID set. Contact jane2 = new Contact(FirstName='Jane', LastName='Smith', Email='jane.smith@example.com', Description='Prefers to be contacted by email.'); // Upsert the contact by using the idLookup field for matching. upsert jane2 Contact.fields.Email; // Verify that the contact has been updated System.assertEquals('Prefers to be contacted by email.', [SELECT Description FROM Contact WHERE Id=:jane.Id].Description);
- Überprüfen Sie alle Kontakte in Ihrer Organisation.
In Ihrer Organisation sollte nur der Kontakt "Jane Smith" mit der aktualisierten Beschreibung vorhanden sein.
Löschen von Datensätzen
Sie können persistent abgelegte Datensätze mit der Anweisung delete
löschen. Gelöschte Datensätze werden nicht dauerhaft aus Lightning Platform gelöscht, sondern 15 Tage im Papierkorb abgelegt, wo sie wiederhergestellt werden können.
Das folgende Beispiel zeigt, wie alle Kontakte mit dem Nachnamen "Smith" gelöscht werden. Wenn Sie das Beispiel für DML-Massenvorgänge ausgeführt haben, sollte Ihre Organisation bereits über zwei Kontakte mit dem Nachnamen "Smith" verfügen. Führen Sie diesen Codeauszug mit anonymem Apex-Code in der Entwicklerkonsole aus und überprüfen Sie dann, dass keine zwei Kontakte mit dem Nachnamen "Smith" mehr vorhanden sind.
Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith']; delete contactsDel;
Ausnahmen bei DML-Anweisungen
Wenn ein DML-Vorgang fehlschlägt, wird eine Ausnahme des Typs DmlException
zurückgegeben. Sie können Ausnahmen in Ihrem Code abfangen, um Fehlerbedingungen zu behandeln.
Das folgende Beispiel erzeugt eine DmlException
, da versucht wird, einen Account ohne das Pflichtfeld "Name" einzufügen. Die Ausnahme wird im Abfangblock abgefangen.
try { // This causes an exception because // the required Name field is not provided. Account acct = new Account(); // Insert the account insert acct; } catch (DmlException e) { System.debug('A DML exception has occurred: ' + e.getMessage()); }
"Database"-Methoden
Apex enthält die integrierte Klasse "Database", die Methoden bereitstellt, die DML-Vorgänge ausführen und die Gegenstücke von DML-Anweisungen darstellen.
Diese "Database"-Methoden sind statisch und werden für den Klassennamen aufgerufen.
Database.insert()
Database.update()
Database.upsert()
Database.delete()
Database.undelete()
Database.merge()
Im Gegensatz zu DML-Anweisungen weisen "Database"-Methoden den optionalen Parameter "allOrNone" auf, mit dem Sie angeben können, ob der Vorgang teilweise erfolgreich sein soll. Wenn dieser Parameter auf "false
" (falsch) festgelegt ist und in einer Teilmenge der Datensätze Fehler auftreten, werden die erfolgreichen Datensätze übernommen und für die fehlgeschlagenen Datensätze werden Fehler zurückgegeben. Zudem werden mit der Option für Teilerfolg keine Ausnahmen ausgelöst.
Die Methode insert
mit auf false
festgelegtem "allOrNone" wird wie folgt aufgerufen.
Database.insert(recordList, false);
Die "Database"-Methoden geben Ergebnisobjekte mit Informationen über Erfolg oder Fehlschlag für jeden Datensatz zurück. Einfüge- und Aktualisierungsvorgänge beispielsweise geben jeweils ein Array von "Database.SaveResult
"-Objekten zurück.
Database.SaveResult[] results = Database.insert(recordList, false);
Der Parameter "allOrNone" ist standardmäßig auf true
(wahr) festgelegt, was bedeutet, dass sich die "Database"-Methode wie die ihr entsprechende DML-Anweisung verhält und eine Ausnahme auslöst, wenn ein Fehler auftritt.
Die folgenden beiden Anweisungen entsprechen der Anweisung "insert recordList;
".
Database.insert(recordList);
Und:
Database.insert(recordList, true);
Beispiel: Einfügen von Datensätzen mit Teilerfolg
Sehen wir uns ein Beispiel an, in dem "Database"-Methode verwendet werden. Dieses Beispiel beruht auf dem Beispiel für DML-Massenvorgänge, verwendet jedoch anstelle der DML-Anweisung eine "Database"-Methode. Die Methode Database.insert()
wird mit der Option für Teilerfolg aufgerufen. Ein Kontakt in der Liste verfügt absichtlich über keine Felder und führt zu einem Fehler, da der Kontakt ohne das Pflichtfeld "LastName" nicht gespeichert werden kann. Drei Kontakte werden übernommen und der Kontakt ohne Felder löst einen Fehler aus. Der letzte Teil dieses Beispiels durchläuft die zurückgegebenen Ergebnisse und schreibt Debug-Meldungen ins Debug-Protokoll.
- Führen Sie dieses Beispiel im Fenster für die anonyme Ausführung der Entwicklerkonsole aus.
// Create a list of contacts List<Contact> conList = new List<Contact> { new Contact(FirstName='Joe',LastName='Smith',Department='Finance'), new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'), new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'), new Contact()}; // Bulk insert all contacts with one DML call Database.SaveResult[] srList = Database.insert(conList, false); // Iterate through each returned result for (Database.SaveResult sr : srList) { if (sr.isSuccess()) { // Operation was successful, so get the ID of the record that was processed System.debug('Successfully inserted contact. Contact ID: ' + sr.getId()); } else { // Operation failed, so get all errors for(Database.Error err : sr.getErrors()) { System.debug('The following error has occurred.'); System.debug(err.getStatusCode() + ': ' + err.getMessage()); System.debug('Contact fields that affected this error: ' + err.getFields()); } } }
- Kontrollieren Sie die Debug-Meldungen (verwenden Sie im Filter das Stichwort DEBUG).
Ein Fehler sollte gemeldet und drei Kontakte sollten eingefügt worden sein.
Sollten DML-Anweisungen oder "Database"-Methoden verwendet werden?
- Verwenden Sie DML-Anweisungen, wenn alle Fehler, die bei der DML-Massenverarbeitung auftreten, eine Apex-Ausnahme auslösen sollen, die den Steuerfluss sofort unterbricht (mithilfe von
try...catch
-Blöcken). Dieses Verhalten ähnelt der Art und Weise, wie Ausnahmen in den meisten prozeduralen Datenbanksprachen behandelt werden.
- Verwenden Sie Methoden der Klasse "Database", wenn Sie einen Teilerfolg eines DML-Massenvorgangs zulassen möchten – wenn bei einem Datensatz ein Fehlschlag auftritt, kann der Rest des DML-Vorgangs dennoch erfolgreich sein. Ihre Anwendung kann dann die zurückgewiesenen Datensätze prüfen und den Vorgang möglicherweise erneut versuchen. Bei Verwendung dieser Form können Sie Code schreiben, der nie DML-Ausnahmefehler auslöst. Stattdessen kann Ihr Code das geeignete Ergebnis-Array zur Unterscheidung zwischen Erfolg und Fehlschlag verwenden. Beachten Sie, dass "Database"-Methoden auch eine Syntax enthalten, die ausgelöste Ausnahmen unterstützt, ähnlich wie DML-Anweisungen.
Arbeiten mit zugehörigen Datensätzen
Sie können Datensätze erstellen und bearbeiten, die über Beziehungen miteinander verknüpft sind.
Einfügen zugehöriger Datensätze
Sie können mit vorhandenen Datensätzen verknüpfte Datensätze einfügen, wenn zwischen den beiden Objekten bereits eine Beziehung definiert wurde, wie etwa eine Nachschlage- oder Master-Detail-Beziehung. Ein Datensatz wird über eine Fremdschlüssel-ID einem verknüpften Datensatz zugeordnet. Beim Einfügen eines neuen Kontakts beispielsweise können Sie den verknüpften Accountdatensatz des Kontakts angeben, indem Sie den Wert des Felds AccountId
festlegen.
Das folgende Beispiel zeigt, wie ein Kontakt durch Festlegen des Felds AccountId
im Kontakt einem Account (dem zugehörigen Datensatz) hinzugefügt wird. Kontakt und Account werden über eine Nachschlagebeziehung miteinander verknüpft.
- Führen Sie diesen Codeauszug im Fenster für anonymen Apex-Code der Entwicklerkonsole aus.
Account acct = new Account(Name='SFDC Account'); insert acct; // Once the account is inserted, the sObject will be // populated with an ID. // Get this ID. ID acctID = acct.ID; // Add a contact to this account. Contact mario = new Contact( FirstName='Mario', LastName='Ruiz', Phone='415.555.1212', AccountId=acctID); insert mario;
- Überprüfen Sie die Kontakte in Ihrer Organisation.
Es wurde ein neuer Account (SFDC Account) erstellt, der in der Themenliste "Kontakte" des Accounts den Kontakt "Mario Ruiz" enthält.
Aktualisieren zugehöriger Datensätze
Felder in zugehörigen Datensätzen können nicht mit demselben Aufruf an den DML-Vorgang aktualisiert werden, sondern erfordern einen separaten DML-Aufruf. Beim Einfügen eines neuen Kontakts beispielsweise können Sie den verknüpften Accountdatensatz des Kontakts angeben, indem Sie den Wert des Felds AccountId
festlegen. Sie können jedoch den Namen des Accounts nicht ändern, ohne den Account selbst mit einem separaten DML-Aufruf zu aktualisieren. Auch beim Aktualisieren eines Kontakts müssen Sie entsprechend zwei DML-Aufrufe verwenden, wenn Sie auch den verknüpften Account des Kontakts aktualisieren möchten. Im folgenden Beispiel werden ein Kontakt und der zugehörige Account mithilfe von zwei update
-Anweisungen aktualisiert.
// Query for the contact, which has been associated with an account. Contact queriedContact = [SELECT Account.Name FROM Contact WHERE FirstName = 'Mario' AND LastName='Ruiz' LIMIT 1]; // Update the contact's phone number queriedContact.Phone = '(415)555-1213'; // Update the related account industry queriedContact.Account.Industry = 'Technology'; // Make two separate calls // 1. This call is to update the contact's phone. update queriedContact; // 2. This call is to update the related account's Industry field. update queriedContact.Account;
Löschen zugehöriger Datensätze
Der delete
-Vorgang unterstützt kaskadierende Löschvorgänge. Wenn Sie ein übergeordnetes Objekt löschen, werden dessen untergeordnete Objekte automatisch gelöscht, solange jeder untergeordnete Datensatz gelöscht werden kann.
Durch Löschen des zuvor erstellten Accounts (SFDC Account) beispielsweise wird auch der damit verknüpfte Kontakt gelöscht.
- Führen Sie diesen Codeauszug im Fenster für anonymen Apex-Code der Entwicklerkonsole aus.
Account[] queriedAccounts = [SELECT Id FROM Account WHERE Name='SFDC Account']; delete queriedAccounts;
- Überprüfen Sie die Accounts und Kontakte in Ihrer Organisation.
Sowohl der Account als auch der damit verknüpfte Kontakt sollten gelöscht worden sein.
Informationen über Transaktionen
DML-Vorgänge werden in einer Transaktion ausgeführt. Entweder werden alle DML-Vorgänge in einer Transaktion vollständig abgeschlossen oder (wenn ein Fehler bei einem Vorgang auftritt) die gesamte Transaktion wird per Rollback zurückgesetzt und keinerlei Daten werden an die Datenbank übergeben. Als Begrenzung für Transaktionen können Auslöser, Klassenmethoden, anonyme Codeblöcke, Apex-Seiten und benutzerdefinierte Webservicemethoden fungieren. Wenn durch einen Auslöser oder eine Klasse beispielsweise zwei Accounts erstellt werden und ein Kontakt aktualisiert wird und die Aktualisierung des Kontakts fehlschlägt, da eine Validierungsregel fehlschlägt, wird die gesamte Transaktion per Rollback zurückgesetzt und keiner der Accounts wird in Salesforce persistent abgelegt.
Ressourcen
- Apex Developer Guide
- Apex Developer Guide: Working with Data in Apex
- Apex Developer Guide: Adding and Retrieving Data With DML
- Apex Developer Guide: Database Class
- Apex Developer Guide: Exception Statements