DML로 레코드 조작하기
학습 목표
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 문
다음 DML 문을 사용할 수 있습니다.
insert
update
upsert
delete
undelete
merge
각 DML 문은 단일 sObject 또는 sObject 목록(또는 배열)을 허용합니다. sObject 목록에 대한 작업은 레코드를 처리하는 더 효율적인 방법입니다.
몇 가지를 제외한 모든 문은 친숙한 데이터베이스 작업입니다. upsert
및 merge
문은 Salesforce에만 해당되며 매우 편리할 수 있습니다.
upsert
DML 작업 은 단일 문 내에서 새 레코드를 만들고 지정된 필드를 사용하여 기존 개체의 존재 여부를 확인하거나 필드가 지정되지 않은 경우 ID 필드를 사용하여 sObject 레코드를 업데이트합니다.
merge
문은 동일한 sObject 유형의 레코드를 최대 3개까지 레코드 중 하나로 병합하고 다른 레코드를 삭제하고 관련 레코드를 다시 상위 항목으로 지정합니다.
새 레코드에 자동 할당된 ID 필드
레코드를 삽입할 때 시스템은 각 레코드에 ID를 할당합니다. 데이터베이스에서 ID 값을 유지하는 것 외에도 ID 값은 DML 호출에서 인수로 사용한 sObject 변수에도 자동으로 채워집니다.
이 예는 삽입된 계정에 해당하는 sObject에서 ID를 가져오는 방법을 보여줍니다.
// 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
단일 sObject 또는 sObject 목록에서 대량으로 DML 작업을 수행할 수 있습니다. 대량 DML 작업을 수행하는 것은 Apex 트랜잭션당 150개의 문으로 된 DML 제한과 같은 거버너 제한에 도달하는 것을 방지하는 데 도움이 되므로 권장되는 방법입니다. Lightning Platform의 공유 리소스에 대한 공정한 액세스를 보장하기 위한 제한 사항입니다. sObject 목록에서 DML 작업을 수행하는 것은 각 sObject에 대한 단일 문이 아니라 하나의 DML 문으로 계산됩니다.
이 예에서는 하나의 호출에 연락처 목록을 삽입하여 연락처를 대량으로 삽입합니다. 그런 다음 샘플은 해당 연락처도 대량으로 업데이트합니다.
- 익명 Apex를 사용하여 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(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;
- 조직에서 최근에 만든 연락처를 검사합니다.
재무 부서에 있는 두 연락처의 직함은Financial analyst
로 채워져야 합니다.
레코드 업서트
새 레코드와 기존 레코드가 혼합된 목록이 있는 경우 upsert
문을 사용하여 목록의 모든 레코드에 대한 삽입 및 업데이트를 처리할 수 있습니다. Upsert는 중복 레코드 생성을 방지하고 어떤 레코드가 먼저 존재하는지 결정할 필요가 없으므로 시간을 절약할 수 있습니다.
upsert
문은 한 필드의 값을 비교하여 sObject를 기존 레코드와 일치시킵니다. 이 문을 호출할 때 필드를 지정하지 않을 경우 upsert
문은 sObject의 ID를 사용하여 sObject를 Salesforce의 기존 레코드와 일치시킵니다. 또는 일치에 사용할 필드를 지정할 수 있습니다. 사용자 정의 개체의 경우 외부 ID로 표시된 사용자 정의 필드를 지정합니다. 표준 개체의 경우 idLookup 속성이 true로 설정된 모든 필드를 지정할 수 있습니다. 예를 들어 연락처 또는 사용자의 이메일 필드에는 idLookup 속성 집합이 있습니다. 필드의 속성을 확인하려면 Salesforce 및 Lightning Platform용 개체 참조를 참조하세요.
Upsert 구문
upsert sObject | sObject[]
upsert sObject | sObject[]
field
upsert sObjectList Account.Fields.MyExternalId;
upsert는 sObject 레코드의 기본 키(ID), idLookup 필드 또는 외부 ID 필드를 사용하여 새 레코드를 생성해야 하는지 아니면 기존 레코드를 업데이트해야 하는지를 결정합니다.
- 키가 일치하지 않으면 새 개체 레코드가 생성됩니다.
- 키가 한 번 일치하면 기존 개체 레코드가 업데이트됩니다.
- 키가 여러 번 일치하면 오류가 발생되고 개체 레코드가 삽입되거나 업데이트되지 않습니다.
이 예에서는 upsert가 기존 연락처 레코드를 업데이트하고 한 통화에 새 연락처를 삽입하는 방법을 보여줍니다. 이 upsert 호출은 기존 Josh 연락처를 업데이트하고 새 연락처 Kathy를 삽입합니다.
- Developer Console의 Execute Anonymous(익명 실행) 창에서 이 코드 조각을 실행합니다.
// 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.
- 조직의 모든 연락처를 검사합니다.
upsert 작업이 새 연락처 레코드를 만드는 대신 기존 레코드를 찾아 업데이트했으므로 조직에는 두 개가 아닌 하나의 Josh Kaplan 레코드만 있습니다. Kathy Brown 연락처 레코드 한 개도 있을 것입니다.
또는 일치하는 레코드에 사용할 필드를 지정할 수 있습니다. 이 예에서는 idLookup 속성 집합을 가지므로 연락처의 이메일 필드를 사용합니다. 이 예에서는 Jane Smith 연락처를 삽입하고 두 번째 연락처 sObject를 만들고 동일한 이메일로 채운 다음 upsert
를 호출하여 일치를 위해 이메일 필드를 사용하여 연락처를 업데이트합니다.
- Developer Console의 Execute Anonymous(익명 실행) 창에서 이 코드 조각을 실행합니다.
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);
- 조직의 모든 연락처를 검사합니다.
조직에는 업데이트된 설명이 포함된 Jane Smith 연락처가 하나만 있습니다.
레코드 삭제
delete
문을 사용하여 지속 레코드를 삭제할 수 있습니다. 삭제된 레코드는 Lightning Platform에서 영구적으로 삭제되지 않지만 복원할 수 있는 위치에서 15일 동안 휴지통에 보관됩니다.
이 예는 성이 Smith인 모든 연락처를 삭제하는 방법을 보여줍니다. 대량 DML에 대한 샘플을 실행한 경우 조직에 이미 성이 Smith인 두 개의 연락처가 있어야 합니다. 익명 Apex를 사용하여 Developer Console에서 이 코드 조각을 실행한 다음 이름이 Smith인 연락처가 더 이상 없는지 확인합니다.
Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith']; delete contactsDel;
DML 문 예외
DML 작업이 실패하면 DmlException
유형의 예외가 반환됩니다. 코드에서 예외를 포착하여 오류 조건을 처리할 수 있습니다.
필수 이름 필드 없이 계정을 삽입하려고 시도하므로 이 예는 DmlException
을 생성합니다. 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()); }
Database 메서드
이러한 Database 메서드는 정적이며 클래스 이름에서 호출됩니다.
Database.insert()
Database.update()
Database.upsert()
Database.delete()
Database.undelete()
Database.merge()
DML 문과 달리 Database 메서드에는 작업이 부분적으로 성공해야 하는지 여부를 지정할 수 있는 allOrNone 매개변수(선택 사항)가 있습니다. 이 매개변수가 false
로 설정된 경우 일부 레코드 집합에서 오류가 발생하면 성공한 레코드가 커밋되고 실패한 레코드에 대해 오류가 반환됩니다. 또한 부분 성공 옵션에서는 예외가 발생하지 않습니다.
allOrNone이 false
로 설정된 insert
메서드를 호출하는 방식입니다.
Database.insert(recordList, false);
Database 메서드는 각 레코드에 대한 성공 또는 실패 정보가 포함된 결과 개체를 반환합니다. 예를 들어 삽입 및 업데이트 작업은 각각 Database.SaveResult
개체의 배열을 반환합니다.
Database.SaveResult[] results = Database.insert(recordList, false);
기본적으로 allOrNone 매개변수는 true
로, 이는 Database 메서드가 DML 문과 동일하게 동작하고 오류가 발생할 경우 예외를 출력한다는 것을 의미합니다.
다음 두 가지 문은 insert recordList;
문과 같습니다.
Database.insert(recordList);
및
Database.insert(recordList, true);
예: 일부 성공한 레코드 삽입
Database 메서드를 사용하는 예를 살펴보겠습니다. 이 예제는 대량 DML 예제를 기반으로 하지만 DML 문을 Database 메서드로 대체합니다. Database.insert()
메서드는 일부 성공 옵션과 함께 호출됩니다. 목록의 한 연락처에는 의도적으로 필드가 없으며 필수 LastName 필드 없이 연락처를 저장할 수 없으므로 오류가 발생합니다. 세 개의 연락처가 커밋되고 필드가 없는 연락처는 오류를 생성합니다. 이 예제의 마지막 부분은 반환된 결과를 반복하고 디버그 메시지를 디버그 로그에 씁니다.
- Developer Console의 Execute Anonymous(익명 실행) 창에서 이 예제를 실행합니다.
// 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()); } } }
- 디버그 메시지를 확인합니다(필터에 DEBUG 키워드 사용).
하나의 실패가 보고되어야 하고 세 개의 연락처가 삽입되어야 합니다.
DML 문 또는 Database 메서드를 사용해야 하나요?
- 대량 DML 처리 중에 발생하는 오류가 제어 플로를 즉시 중단하는 Apex 예외로 출력되도록 하려면 DML 문을 사용합니다(
try...catch
블록 사용). 이 동작은 대부분의 데이터베이스 절차 언어에서 예외가 처리되는 방식과 유사합니다. - 대량 DML 작업의 부분적인 성공을 허용하려면 Database 클래스 메서드를 사용하세요. 레코드가 실패하더라도 나머지 DML 작업은 계속 성공할 수 있습니다. 그러면 애플리케이션에서 거부된 레코드를 검사하고 작업을 재시도할 수 있습니다. 이 양식을 사용하면 DML 예외 오류가 발생하지 않는 코드를 작성할 수 있습니다. 대신 코드에서 적절한 결과 배열을 사용하여 성공 또는 실패를 판단할 수 있습니다. Database 메서드에는 DML 문과 유사하게 출력된 예외를 지원하는 구문도 포함되어 있습니다.
리소스
- Apex 개발자 가이드
- Apex 개발자 가이드: Apex에서 데이터 작업
- Apex 개발자 가이드: DML로 데이터 추가 및 검색
- Apex 개발자 가이드: 데이터베이스 클래스