Bearbeiten von Datensätzen mit DML
Lernziele
- 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
// 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
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
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 allOrNone festgelegt auf "false
" 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.
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