Manipular registros com DML
Objetivos de aprendizagem
- 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
// 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
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. Este 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
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 possuem 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
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 possui nenhum campo propositalmente 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.
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