Manipulation des enregistrements avec le langage DML
Objectifs de formation
Une fois cette unité terminée, vous pourrez :
- Utiliser DML pour insérer, mettre à jour et supprimer des enregistrements
- Exécuter des instructions DML en masse
- Utiliser la mise à jour/insertion pour insérer ou mettre à jour un enregistrement
- Intercepter une exception DML
- Utiliser une méthode Database pour insérer de nouveaux enregistrements avec l'option de succès partiel et traiter les résultats
- Déterminer quand utiliser des instructions DML et des méthodes Database
- Exécuter des opérations DML sur des enregistrements associés
Manipulation des enregistrements avec le langage DML
Le langage DML (Data Manipulation Language) vous permet de créer et de modifier des enregistrements dans Salesforce. DML offre une méthode claire qui permet de gérer les enregistrements à l'aide de simples instructions d'insertion, de mise à jour, de fusion, de suppression et de restauration d'enregistrements.
Apex est un langage orienté vers les données et enregistré sur Lightning Platform. Par conséquent, il a directement accès à vos données dans Salesforce. Contrairement aux autres langages de programmation qui nécessitent une configuration supplémentaire pour se connecter aux sources de données, le langage DML Apex facilite la gestion des enregistrements ! En appelant des instructions DML, vous pouvez exécuter rapidement des opérations sur vos enregistrements Salesforce. Cet exemple ajoute le compte Acme à Salesforce. Un sObject de compte est créé, puis transmis en tant qu’argument à l’instruction insert, qui conserve l’enregistrement dans Salesforce.
// Create the account sObject Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100); // Insert the account by using DML insert acct;
Instructions DML
Les instructions DML disponibles sont les suivantes :
insert
update
upsert
delete
undelete
merge
Chaque instruction DML accepte un sObject unique ou une liste (ou un tableau) de sObjects. L'utilisation d'une liste de sObjects est plus efficace pour traiter les enregistrements.
La plupart de ces instructions sont des opérations de base de données connues. Les instructions upsert
et merge
sont propres à Salesforce et peuvent se révéler très utiles.
L’opération DML upsert
crée des enregistrements et met à jour des enregistrements sObject dans une instruction unique, à l’aide d’un champ défini pour déterminer la présence d’objets existants, ou du champ ID si aucun champ n’est spécifié.
L'instruction merge
fusionne jusqu'à trois enregistrements du même type de sObject dans l'un des enregistrements, supprime les autres, et attribue un nouveau parent à tous les enregistrements associés.
Champ ID attribué automatiquement aux nouveaux enregistrements
Lors de l'insertion d'enregistrements, le système attribue un ID à chaque enregistrement. La valeur ID est conservée dans la base de données et automatiquement renseignée dans la variable sObject que vous avez utilisée comme argument dans l’appel DML.
L'exemple ci-dessous montre comment obtenir l'ID du sObject qui correspond au compte inséré.
// 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 en masse
Vous pouvez effectuer des opérations DML sur un sObject unique ou en masse dans une liste de sObjects. L’option d’exécution en masse d’opérations DML est recommandée pour ne pas atteindre les limitations du gouverneur, notamment la limitation DML de 150 instructions par transaction Apex. Cette limitation garantit un accès équitable aux ressources partagées sur Lightning Platform. L'exécution d'une opération DML dans une liste de sObjects est prise en compte comme une seule instruction DML, pas une instruction pour chaque sObject individuel.
Cet exemple insère des contacts en masse en ajoutant la liste de contacts à un seul appel. L'exemple met ensuite à jour ces contacts en masse.
- Exécutez l'extrait ci-dessous dans la Developer Console à l'aide d'un Apex anonyme.
// 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;
- Examinez les contacts récemment créés dans votre organisation.
La fonction de deux contacts appartenant au service Finance doit être renseignée avecFinancial analyst
(Analyste financier).
Mise à jour/insertion d’enregistrements
Si vous avez une liste contenant aussi bien des enregistrements existants que nouveaux, vous pouvez traiter les insertions et les mises à jour de tous les enregistrements de la liste à l'aide de l'instruction upsert
. La mise à jour/insertion évite la création d’enregistrements dupliqués. Il n’est pas nécessaire de déterminer au préalable quels sont les enregistrements existants, ce qui peut représenter un gain de temps.
L'instruction upsert
mappe les sObjects avec les enregistrements existants en comparant les valeurs d'un champ. Si vous ne spécifiez aucun champ lors de l'appel de cette instruction, l'instruction upsert
utilise l'ID du sObject pour mapper le sObject avec des enregistrements existants dans Salesforce. Vous pouvez également spécifier le champ de mappage à utiliser. Pour des objets personnalisés, spécifiez un champ personnalisé marqué comme ID externe. Pour des objets standard, vous pouvez spécifier n’importe quel champ dont la propriété idLookup est définie sur true. Par exemple, le champ Email (E-mail) de l’objet Contact ou User (Utilisateur) dispose d’une propriété idLookup définie. Pour vérifier la propriété d’un champ, reportez-vous à Référence d’objet pour Salesforce et la plate-forme Lightning.
Syntaxe de mise à jour/insertion
upsert sObject | sObject[] upsert sObject | sObject[] field
Le champ facultatif est un jeton de champ. Par exemple, pour spécifier le champ MyExternalID, l'instruction est la suivante :
upsert sObjectList Account.Fields.MyExternalId;
La mise à jour/insertion utilise la clé primaire (ID) de l'enregistrement du sObject, un champ idLookup ou un champ ID externe afin de déterminer si un enregistrement doit être créé ou si un enregistrement existant doit être mis à jour :
- Si la clé n'a aucune correspondance, un enregistrement d'objet est créé.
- Si la clé a une correspondance, l'enregistrement d'objet existant est mis à jour.
- Si la clé a plusieurs correspondances, une erreur est générée et l'enregistrement de l'objet n'est pas inséré ni mis à jour.
L'exemple ci-dessous montre comment l’opération de mise à jour/insertion met à jour un enregistrement de contact existant et insère un nouveau contact au cours d’un seul appel. Cet appel met à jour le contact existant Josh et insère le nouveau contact Kathy.
- Exécutez l'extrait ci-dessous dans la fenêtre Execute Anonymous (Exécution anonyme) de la Developer Console.
// 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.
- Examinez tous les contacts de votre organisation.
Votre organisation contient un seul enregistrement Josh Kaplan, pas deux, car l’opération de mise à jour/insertion a retrouvé l’enregistrement existant et l’a mis à jour, sans créer un enregistrement de contact. L'enregistrement de contact Kathy Brown existe également.
Vous pouvez également spécifier le champ à utiliser pour mettre en correspondance les enregistrements. Cet exemple utilise le champ Email (E-mail) sur Contact, car sa propriété idLookup est définie. L'exemple insère le contact Jane Smith, crée un deuxième sObject Contact (Contact), le renseigne avec la même adresse e-mail, puis appelle upsert
pour mettre à jour le contact en utilisant le champ Email (E-mail) à des fins de mise en correspondance.
- Exécutez l'extrait ci-dessous dans la fenêtre Execute Anonymous (Exécution anonyme) de la Developer Console.
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);
- Examinez tous les contacts de votre organisation.
Votre organisation contient un seul contact Jane Smith avec la description mise à jour.
Suppression d’enregistrements
Vous pouvez supprimer des enregistrements permanents à l'aide de l'instruction delete
. Les enregistrements ne sont pas définitivement supprimés de la plate-forme Lightning, mais ils sont placés dans la corbeille pendant 15 jours, période pendant laquelle ils peuvent être restaurés.
L'exemple ci-dessous montre comment supprimer tous les contacts qui portent le nom Smith. Si vous avez exécuté l’exemple relatif au DML en masse, votre organisation doit contenir deux contacts Smith. Exécutez cet extrait de code dans la Developer Console à l'aide d'Apex anonyme, puis vérifiez qu'il n'existe plus aucun contact Smith.
Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith']; delete contactsDel;
Exceptions d'instruction DML
Si une opération DML échoue, elle renvoie une exception de type DmlException
. Vous pouvez saisir des exceptions dans votre code pour gérer les conditions d'erreur.
Cet exemple produit une DmlException
, car il tente d'insérer un compte sans le champ obligatoire Name (Nom). L'exception est interceptée dans le bloc catch.
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()); }
Méthodes Database
Apex contient la classe Database intégrée. Cette dernière fournit des méthodes qui exécutent des opérations DML et reproduisent les instructions DML équivalentes.
Les méthodes Database ci-dessous sont statiques et sont appelées dans le nom de la classe.
Database.insert()
Database.update()
Database.upsert()
Database.delete()
Database.undelete()
Database.merge()
Contrairement aux instructions DML, les méthodes Database ont un paramètre facultatif allOrNone qui permet de spécifier si l’opération doit être partiellement réussie. Lorsque ce paramètre est défini sur false
, si des erreurs se produisent sur un ensemble partiel d'enregistrements, les enregistrements réussis sont acceptés et des erreurs sont renvoyées pour les enregistrements échoués. En outre, avec l'option de succès partiel, aucune exception n'est renvoyée.
Voici comment vous appelez la méthode insert
avec le paramètre allOrNone défini sur false
.
Database.insert(recordList, false);
Les méthodes Database renvoient des objets de résultat qui contiennent des informations sur la réussite ou l'échec de chaque enregistrement. Par exemple, les opérations d'insertion et de mise à jour renvoient chacune un tableau d'objets Database.SaveResult
.
Database.SaveResult[] results = Database.insert(recordList, false);
Par défaut, le paramètre allOrNone est défini sur true
, ce qui signifie que la méthode Database se comporte comme son instruction DML équivalente et renvoie une exception en cas d’échec.
Les deux instructions suivantes sont équivalentes à l'instruction insert recordList;
.
Database.insert(recordList);
Et :
Database.insert(recordList, true);
Exemple : insertion d’enregistrements avec l’option de succès partiel
Examinons un exemple de l'utilisation des méthodes Database. Cet exemple s’appuie sur celui relatif à DML en masse, mais remplace l'instruction DML par une méthode Database. La méthode Database.insert()
est appelée avec l'option de succès partiel. Un contact de la liste n’a volontairement aucun champ, ce qui entraîne une erreur, car il ne peut pas être enregistré sans le champ obligatoire LastName. Trois contacts sont acceptés et le contact sans champ génère une erreur. La dernière partie de cet exemple reprend les résultats renvoyés et écrit des messages de débogage dans le journal de débogage.
- Exécutez cet exemple dans la fenêtre Execute Anonymous (Exécution anonyme) de la Developer Console.
// 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()); } } }
- Vérifiez les messages de débogage (utilisez le mot clé DEBUG pour le filtre).
Un échec doit être consigné et trois contacts doivent être insérés.
Comparaison entre les instructions DML et les méthodes Database
- Utilisez des instructions DML pour générer les erreurs rencontrées lors du traitement DML en masse sous la forme d’une exception Apex qui interrompt immédiatement le flux de contrôle (en utilisant des blocs
try...catch
). Ce comportement est semblable au traitement des exceptions dans la plupart des langages de procédure de base de données.
- Utilisez des méthodes de classe Database pour autoriser le succès partiel d'une opération DML en masse. Si un enregistrement échoue, le reste de l'opération DML peut réussir. Votre application peut ensuite inspecter les enregistrements refusés et éventuellement retenter l'opération. Lors de l'utilisation de ce formulaire, vous pouvez écrire un code qui ne renvoie jamais d'erreur d'exception DML. À la place, votre code peut utiliser le tableau de résultats approprié pour déterminer la réussite ou l'échec. De la même façon que les instructions DML, les méthodes Database incluent une syntaxe qui prend en charge les exceptions renvoyées.
Utilisation d'enregistrements associés
Créez et gérez des enregistrements associés à l'aide de relations.
Insertion d’enregistrements associés
Vous pouvez insérer des enregistrements associés à des enregistrements existants si une relation a été définie entre les deux objets, par exemple une relation de référence ou principal-détails. Un enregistrement est lié à un autre enregistrement par un ID de clé étrangère. Par exemple, en cas d'insertion d'un nouveau contact, vous pouvez spécifier l'enregistrement du compte associé du contact en définissant la valeur du champ AccountId
.
Cet exemple montre comment ajouter un contact à un compte (l'enregistrement associé) en définissant le champ AccountId
du contact. Le contact et le Account (compte) sont liés par une relation de référence.
- Exécutez l'extrait de code ci-dessous dans la fenêtre Anonymous Apex (Apex anonyme) de la Developer Console.
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;
- Examinez les contacts de votre organisation.
Un compte (SFDC Account [Compte SFDC]) a été créé et contient le contact Mario Ruiz dans la liste associée Contacts du compte.
Mise à jour d’enregistrements associés
Les champs d'enregistrements associés ne peuvent pas être mis à jour avec le même appel à l'opération DML et nécessitent un appel DML distinct. Par exemple, en cas d'insertion d'un nouveau contact, vous pouvez spécifier l'enregistrement du compte associé du contact en définissant la valeur du champ AccountId
. Cependant, vous ne pouvez pas modifier le nom du compte sans mettre à jour le compte lui-même avec un appel DML distinct. De même, lors de la mise à jour d'un contact, si vous souhaitez également mettre à jour le compte associé du contact, vous devez émettre deux appels DML. L’exemple suivant met à jour un contact et le compte qui lui est associé à l’aide de deux instructions update
.
// 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;
Suppression d’enregistrements associés
L'opération delete
prend en charge les suppressions en cascade. Si vous supprimez un objet parent, vous supprimez automatiquement ses enfants, si chaque enregistrement enfant peut être supprimé.
Par exemple, la suppression du compte que vous avez créé plus tôt (SFDC Account [Compte SFDC]) entraîne la suppression de son contact associé.
- Exécutez l'extrait de code ci-dessous dans la fenêtre Anonymous Apex (Apex anonyme) de la Developer Console.
Account[] queriedAccounts = [SELECT Id FROM Account WHERE Name='SFDC Account']; delete queriedAccounts;
- Examinez les comptes et les contacts de votre organisation.
Vous verrez que le compte et son contact associé ont été supprimés.
À propos des transactions
Les opérations DML sont exécutées dans une transaction. Toutes les opérations DML d'une transaction réussissent, ou bien la transaction entière est abandonnée et aucune donnée n'est transmise à la base de données si l'opération rencontre une erreur. La limite d'une transaction peut être un déclencheur, une méthode de classe, un bloc de code anonyme, une page Apex ou une méthode de service Web personnalisée. Par exemple, si un déclencheur ou une classe crée deux comptes et met à jour un contact, et si la mise à jour du contact échoue suite à l'échec d'une règle de validation, la transaction entière est abandonnée et aucun compte n'est conservé dans Salesforce.
Ressources
- Guide du développeur Apex
- Guide du développeur Apex : Manipulation de données dans Apex
- Guide du développeur Apex : Ajout et récupération de données avec DML
- Guide du développeur Apex : Classe Database
- Apex Developer Guide: Instructions d’exception