Manipular registros com DML
Objetivos de aprendizagem
Após concluir esta unidade, você estará apto a:
- Usar a DML para inserir, atualizar e excluir registros.
- Executar instruções DML em massa.
- Usar o upsert para inserir ou atualizar um registro.
- Capturar uma exceção de DML.
- Usar um método Database para inserir novos registros com a opção de sucesso parcial e processar os resultados.
- Saber quando usar instruções DML e quando usar métodos Database.
- Executar operações de DML em registros relacionados.
Manipular registros com DML
Crie e modifique registros no Salesforce usando a Data Manipulation Language (Linguagem de manipulação de dados), abreviada como DML. A DML proporciona uma maneira simples de gerenciar registros, fornecendo instruções simples para inserir, atualizar, mesclar, excluir e restaurar registros.
Como Apex é uma linguagem centrada em dados e salva na Lightning Platform, ela tem acesso direto aos seus dados no Salesforce. Ao contrário de outras linguagens de programação que exigem configuração extra para se conectar a fontes de dados, com a DML do Apex é fácil gerenciar registros! Chamando as instruções DML, você pode executar rapidamente operações em seus registros do Salesforce. Neste exemplo a conta Acme é adicionada ao Salesforce. Primeiramente, cria-se um sObject da conta e, em seguida, ele é aprovado como um argumento para a instrução inserir, que persiste o registro no 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;
Demonstrativos DML
As seguintes instruções DML estão disponíveis.
insert
(inserir)update
(atualizar)upsert
(inserir e atualizar)delete
(excluir)undelete
(desfazer exclusão)merge
(mesclar)
Cada instrução DML aceita um único sObject ou uma lista (ou matriz) de sObjects. Operar em uma lista de sObjects é uma maneira mais eficiente de processar registros.
Todas essas instruções, exceto duas, são operações de banco de dados familiares. As instruções upsert
e merge
são específicas do Salesforce e podem ser bastante úteis.
A operação DML upsert
(inserir e atualizar) cria novos registros e atualiza os registros sObject em uma única instrução, usando um campo especificado para determinar a presença de objetos existentes ou o campo de ID caso nenhum campo seja especificado.
A instrução merge
mescla até três registros do mesmo tipo de sObject em um dos registros, excluindo os demais e reassociando quaisquer registros relacionados.
Campo ID autoatribuído a novos registros
Ao inserir registros, o sistema atribui uma ID a cada um deles. Além de persistir o valor ID no banco de dados, o valor ID também é preenchido automaticamente na variável sObject que você usou como argumento na chamada DML.
Este exemplo mostra como obter a ID do sObject que corresponde à conta inserida.
// 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 em massa
É possível executar operações DML em um único sObject ou em massa, em uma lista de sObjects. Realizar operações DML em massa é a maneira recomendada, porque ajuda a evitar atingir os limites de administrador, tais como o limite DML de 150 instruções por transação do Apex. Esse limite está em vigor para garantir um acesso justo aos recursos compartilhados na Lightning Platform. Executar uma operação DML em uma lista de sObjects conta como uma instrução DML, não como uma instrução para cada sObject.
Este exemplo insere contatos em massa por meio da inserção de uma lista de contatos em uma chamada. Então, a amostra também atualiza esses contatos em massa.
- Execute este trecho de código no Developer Console usando o Apex anônimo.
// 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;
- Inspecione os contatos recém-criados em sua organização.
Dois dos contatos que estão no departamento financeiro devem ter seus títulos preenchidos comFinancial analyst
(Analista financeiro).
Inserir e atualizar registros
Se você tem uma lista que contém uma mistura de registros novos e existentes, pode processar inserções e atualizações de todos os registros da lista usando a instrução upsert
. Essa instrução ajuda a evitar a criação de registros duplicados e pode ajudá-lo a ganhar tempo, já que você não tem que determinar quais registros foram criados primeiro.
A instrução upsert
coincide com os sObjects com registros existentes, comparando os valores de um campo. Se você não especificar um campo ao chamar esta instrução, a instrução upsert
usa a ID do sObject para coincidir o sObject com os registros existentes no Salesforce. Você também pode especificar um campo para usar como correspondência. Para objetos personalizados, especifique um campo personalizado marcado como ID externa. Para objetos padrão, você pode especificar qualquer campo que tenha a propriedade idLookup definida como verdadeira. Por exemplo, o campo Email de Contato ou Usuário tem a propriedade idLookup definida. Para verificar a propriedade de um campo, consulte Referência de objeto para Salesforce e Lightning Platform.
Sintaxe de inserir e atualizar
upsert sObject | sObject[] upsert sObject | sObject[] field
O campo opcional é um token de campo. Por exemplo, para especificar o campo MyExternalID, a instrução é:
upsert sObjectList Account.Fields.MyExternalId;
A instrução inserir e atualizar usa a chave primária do registro sObject (a ID), um campo idLookup ou um campo de ID externa para determinar se deve criar um novo registro ou atualizar um registro existente:
- Se a chave não for correspondida, um novo registro de objeto é criado.
- Se a chave for correspondida uma vez, o registro de objeto existente é atualizado.
- Se a chave for correspondida várias vezes, um erro é gerado e o registro de objeto não é inserido nem atualizado.
Este exemplo mostra como a instrução "inserir e atualizar" atualiza um registro de contato existente e insere um novo contato em uma chamada. Esta chamada de inserção e atualização atualiza o contato Josh existente e insere um novo contato: Kathy.
- Execute este trecho de código na janela Executar anônimo do 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.
- Inspecione todos os contatos da sua organização.
Sua organização terá apenas um registro Josh Kaplan e não dois, porque a operação de inserção e atualização encontrou o registro existente e o atualizou em vez de criar um novo registro de contato. Um registro de contato Kathy Brown também estará lá.
Você também pode especificar um campo a ser usado para registros correspondentes. Esse exemplo usa o campo Email no Contato porque tem a propriedade idLookup definida. O exemplo insere o contato Jane Smith e cria um segundo contato sObject. Em seguida, preenche-o com o mesmo email e, finalmente, efetua a chamada upsert
para atualizar o contato usando o campo de email para correspondência.
- Execute este trecho de código na janela Executar anônimo do 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);
- Inspecione todos os contatos da sua organização.
Sua organização terá apenas um contato Jane Smith com a descrição atualizada.
Excluir registros
Você pode excluir registros persistentes usando a instrução delete
. Os registros excluídos não são excluídos permanentemente da Lightning Platform, mas são colocados na Lixeira por 15 dias, de onde podem ser restaurados.
Este exemplo mostra como excluir todos os contatos com sobrenome Smith. Se você executar o exemplo para a DML em massa, sua organização já deverá ter dois contatos com o sobrenome Smith. Execute este trecho de código no Developer Console usando o Apex anônimo e, em seguida, verifique se já não há contatos com o sobrenome Smith.
Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith']; delete contactsDel;
Exceções da instrução DML
Se uma operação DML falha, ela retorna uma exceção do tipo DmlException
. Você pode capturar exceções em seu código para lidar com situações de erro.
Este exemplo produz uma DmlException
por tentar inserir uma conta sem o campo de Nome obrigatório. A exceção é detectada no bloco 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étodos Database
O Apex contém a classe Database integrada, que fornece métodos que executam operações DML e espelham as instruções DML equivalentes.
Os métodos Database são estáticos e chamados no nome da classe.
Database.insert()
Database.update()
Database.upsert()
Database.delete()
Database.undelete()
Database.merge()
Diferentemente de instruções DML, métodos Database têm um parâmetro allOrNone opcional que permite que você especifique se a operação pode ser parcialmente bem-sucedida. Quando esse parâmetro está definido como false
, caso ocorram erros em um conjunto parcial de registros, os registros bem-sucedidos serão confirmados e os erros serão retornados para os registros de falha. Além disso, com a opção de sucesso parcial, nenhuma exceção é gerada.
Você chama o método insert
(inserir) com o parâmetro allOrNone definido como false
da seguinte forma.
Database.insert(recordList, false);
Os métodos Database retornam objetos de resultado contendo informações de sucesso ou falha para cada registro. Por exemplo, cada operação de inserir e atualizar retorna uma matriz de objetos Database.SaveResult
.
Database.SaveResult[] results = Database.insert(recordList, false);
Por padrão, o parâmetro allOrNone é definido como true
, o que significa que o método Database se comporta como sua instrução DML equivalente e gera uma exceção se uma falha é encontrada.
As duas instruções a seguir são equivalentes à instrução insert recordList;
.
Database.insert(recordList);
E:
Database.insert(recordList, true);
Exemplo: Inserir registros com sucesso parcial
Vamos examinar um exemplo que utiliza os métodos Database. Este exemplo se baseia no exemplo do DML em massa, mas substitui a instrução DML por um método Database. O método Database.insert()
é chamado com a opção de sucesso parcial. Um contato na lista não tem campos intencionalmente e causará um erro, pois o contato não pode ser salvo sem o campo obrigatório LastName. Três contatos são confirmados e o contato sem campos gera um erro. A última parte deste exemplo itera nos resultados retornados e escreve mensagens de depuração no registro de depuração.
- Execute este exemplo na janela Executar anônimo no 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()); } } }
- Verifique as mensagens de depuração (use a palavra-chave DEBUG para o filtro).
Uma falha deve ser reportada e três contatos devem ter sido inseridos.
Você deve usar instruções DML ou métodos Database?
- Use instruções DML se quiser que qualquer erro que ocorra durante o processamento DML em massa seja gerado como uma exceção do Apex que interrompe imediatamente o fluxo de controle (usando blocos
try...catch
). Esse comportamento é similar à maneira como exceções são tratadas na maioria das linguagens de procedimento de bancos de dados.
- Use métodos de classe Database se quiser permitir o sucesso parcial de uma operação DML em massa — se um registro falhar, o restante da operação DML ainda pode ser bem-sucedida. Seu aplicativo pode então inspecionar os registros rejeitados e possivelmente tentar efetuar a operação novamente. Ao utilizar esse formato, você pode escrever um código que nunca gere erros de exceção de DML. Em vez disso, seu código pode usar a matriz de resultados apropriada para julgar o sucesso ou a falha. Observe que métodos Database também incluem uma sintaxe compatível com exceções geradas, semelhante às instruções DML.
Trabalhar com registros relacionados
Crie e gerencie registros vinculados por relacionamentos.
Inserir registros relacionados
Você pode inserir registros relacionados nos registros existentes caso um relacionamento já tenha sido definido entre os dois objetos, por exemplo, um relacionamento de pesquisa ou um relacionamento entre mestre e detalhes. Um registro é associado a um registro relacionado por um ID de chave estrangeira. Por exemplo, ao inserir um novo contato, é possível especificar o registro de conta relacionado ao contato definindo o valor do campo AccountId
.
Esse exemplo mostra como adicionar um contato a uma conta (o registro relacionado) definindo o campo AccountId
do contato. O contato e a conta são vinculados por um relacionamento de pesquisa.
- Execute este trecho de código na janela Apex anônimo do 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;
- Inspecione os contatos da sua organização.
Uma nova conta (conta SFDC) foi criada, e o contato Mario Ruiz está na lista relacionada Contatos dessa conta.
Atualizar registros relacionados
Não é possível atualizar os campos dos registros relacionados com a mesma chamada para a operação DML. Isso exige uma chamada DML à parte. Por exemplo, ao inserir um novo contato, é possível especificar o registro de conta relacionado ao contato definindo o valor do campo AccountId
. No entanto, não pode alterar o nome da conta sem atualizar a própria conta com uma chamada DML à parte. De modo parecido, ao atualizar um contato, você precisa fazer duas chamadas DML se também quiser atualizar a conta relacionada ao contato. O exemplo a seguir atualiza um contato e a conta relacionada a ele usando duas instruções update
(atualizar).
// 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;
Excluir registros relacionados
A operação delete
permite exclusões em cascata. Quando um objeto pai é excluído, excluem-se automaticamente todos os registros filhos relacionados a ele que puderem ser excluídos.
Por exemplo, se você excluir a conta criada anteriormente (conta SFDC), também excluirá o contato relacionado a ela.
- Execute este trecho de código na janela Apex anônimo do Developer Console.
Account[] queriedAccounts = [SELECT Id FROM Account WHERE Name='SFDC Account']; delete queriedAccounts;
- Verifique as contas e contatos em sua organização.
Você verá que tanto a conta quanto seu contato relacionado foram excluídos.
Sobre as transações
As operações DML são executadas dentro de uma transação. Todas as operações DML em uma transação são concluídas com êxito ou, se um erro ocorrer em uma operação, a transação inteira será revertida e nenhum dado será confirmado no banco de dados. O limite de uma transação pode ser um acionador, um método de classe, um bloco anônimo de código, uma página do Apex ou um método de serviço da Web personalizado. Por exemplo, se um acionador ou uma classe criar duas contas e atualizar um contato, mas a atualização do contato falhar por causa de um erro na regra de validação, a transação inteira será revertida e nenhuma das contas permanecerá no Salesforce.
Recursos
- Apex Developer Guide
- Guia do desenvolvedor do Apex: Working with Data in Apex
- Guia do desenvolvedor do Apex: Adding and Retrieving Data With DML
- Guia do desenvolvedor do Apex: Database Class
- Guia do desenvolvedor do Apex: Instruções de exceção