Skip to main content

DML로 레코드 조작하기

학습 목표

이 유닛을 완료하면 다음을 수행할 수 있습니다.

  • DML을 사용하여 레코드를 삽입, 업데이트 및 삭제할 수 있습니다.
  • 대량으로 DML 문을 수행할 수 있습니다.
  • upsert를 사용하여 레코드를 삽입하거나 업데이트할 수 있습니다.
  • DML 예외를 찾을 수 있습니다.
  • Database 메서드를 사용하여 일부 성공 옵션이 있는 새 레코드를 삽입하고 결과를 처리할 수 있습니다.
  • DML 문을 사용해야 하는 경우와 Database 메서드를 사용해야 하는 경우를 알 수 있습니다.
  • 관련 레코드에 대해 DML 작업을 수행할 수 있습니다.
참고

참고

한국어로 학습하시겠어요? Trailhead playground에서 한국어로 실습 과제를 시작하고, 괄호 안에 제공된 번역을 사용해 탐색해 보세요. 영어 데이터를 기반으로 실습 과제 검증이 이루어지므로 영문으로 표시된 값만 복사해 붙여 넣습니다. 한국어 조직에서 실습 과제를 통과하지 못한 경우, (1) 로캘을 미국을 바꾸고 (2) 여기에 제시된 지침에 따라 언어를 영어로 바꾼 후 (3) "Check Challenge(과제 확인)" 버튼을 눌러 다시 진행해 보세요.

원하는 언어로 Trailhead 사용하기 뱃지를 확인해 현지화된 Trailhead 경험을 활용하는 방법에 대해 자세히 알아보세요.

DML로 레코드 조작하기

Data Manipulation Language(약칭 DML)를 사용하여 Salesforce에서 레코드를 만들고 수정합니다. DML은 레코드를 삽입, 업데이트, 병합, 삭제 및 복원하는 간단한 명령문을 제공하여 레코드를 관리하는 간단한 방법을 제공합니다.

Apex는 데이터 중심 언어이고 Lightning Platform에 저장되기 때문에 Salesforce의 데이터에 직접 액세스할 수 있습니다. 데이터 소스에 연결하기 위해 추가 설정이 필요한 다른 프로그래밍 언어와 달리 Apex DML을 사용하면 레코드 관리가 간편해집니다. DML 문을 호출하여 Salesforce 레코드에 대한 작업을 빠르게 수행할 수 있습니다. 이 예에서는 Acme 계정을 Salesforce에 추가합니다. 계정 sObject가 먼저 생성된 다음 인수를 Salesforce에서 레코드를 유지하는 문인 insert 문에 전달합니다.

// 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 목록에 대한 작업은 레코드를 처리하는 더 효율적인 방법입니다.

몇 가지를 제외한 모든 문은 친숙한 데이터베이스 작업입니다. upsertmerge 문은 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







참고

추가 기본 정보

예제의 sObject 변수에는 DML 호출 후 ID가 포함되어 있으므로 이 sObject 변수를 재사용하여 업데이트와 같은 추가 DML 작업을 수행할 수 있습니다. 왜냐하면 시스템이 ID를 일치시켜 sObject 변수를 해당 레코드에 매핑할 수 있기 때문입니다.

데이터베이스에서 레코드를 검색하여 ID 필드를 포함하여 해당 필드를 가져올 수 있지만 DML에서는 이 작업을 수행할 수 없습니다. SOQL을 사용하여 쿼리를 작성해야 합니다. 다른 유닛에서 SOQL에 대해 알아보겠습니다.

대량 DML

단일 sObject 또는 sObject 목록에서 대량으로 DML 작업을 수행할 수 있습니다. 대량 DML 작업을 수행하는 것은 Apex 트랜잭션당 150개의 문으로 된 DML 제한과 같은 거버너 제한에 도달하는 것을 방지하는 데 도움이 되므로 권장되는 방법입니다. Lightning Platform의 공유 리소스에 대한 공정한 액세스를 보장하기 위한 제한 사항입니다. sObject 목록에서 DML 작업을 수행하는 것은 각 sObject에 대한 단일 문이 아니라 하나의 DML 문으로 계산됩니다.

이 예에서는 하나의 호출에 연락처 목록을 삽입하여 연락처를 대량으로 삽입합니다. 그런 다음 샘플은 해당 연락처도 대량으로 업데이트합니다.

  1. 익명 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;
  2. 조직에서 최근에 만든 연락처를 검사합니다.
    재무 부서에 있는 두 연락처의 직함은 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

선택적 필드는 필드 토큰입니다. 예를 들어 MyExternalID 필드를 지정하는 문은 다음과 같습니다.

upsert sObjectList Account.Fields.MyExternalId;

upsert는 sObject 레코드의 기본 키(ID), idLookup 필드 또는 외부 ID 필드를 사용하여 새 레코드를 생성해야 하는지 아니면 기존 레코드를 업데이트해야 하는지를 결정합니다.

  • 키가 일치하지 않으면 새 개체 레코드가 생성됩니다.
  • 키가 한 번 일치하면 기존 개체 레코드가 업데이트됩니다.
  • 키가 여러 번 일치하면 오류가 발생되고 개체 레코드가 삽입되거나 업데이트되지 않습니다.

이 예에서는 upsert가 기존 연락처 레코드를 업데이트하고 한 통화에 새 연락처를 삽입하는 방법을 보여줍니다. 이 upsert 호출은 기존 Josh 연락처를 업데이트하고 새 연락처 Kathy를 삽입합니다.

참고

참고

upsert 호출은 ID를 사용하여 첫 번째 연락처와 일치시킵니다. josh 변수가 upsert 호출에 재사용되고 있습니다. 이 변수는 이전 삽입 호출의 레코드 ID로 이미 채워져 있으므로 이 예에서 ID를 명시적으로 설정할 필요가 없습니다.

  1. 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.
  2. 조직의 모든 연락처를 검사합니다.
    upsert 작업이 새 연락처 레코드를 만드는 대신 기존 레코드를 찾아 업데이트했으므로 조직에는 두 개가 아닌 하나의 Josh Kaplan 레코드만 있습니다. Kathy Brown 연락처 레코드 한 개도 있을 것입니다.

또는 일치하는 레코드에 사용할 필드를 지정할 수 있습니다. 이 예에서는 idLookup 속성 집합을 가지므로 연락처의 이메일 필드를 사용합니다. 이 예에서는 Jane Smith 연락처를 삽입하고 두 번째 연락처 sObject를 만들고 동일한 이메일로 채운 다음 upsert를 호출하여 일치를 위해 이메일 필드를 사용하여 연락처를 업데이트합니다.

참고

참고

upsert 대신 이 예에서 insert가 사용된 경우 중복된 Jane Smith 연락처가 삽입되었을 수 있습니다.

  1. 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);
  2. 조직의 모든 연락처를 검사합니다.
    조직에는 업데이트된 설명이 포함된 Jane Smith 연락처가 하나만 있습니다.

레코드 삭제

delete 문을 사용하여 지속 레코드를 삭제할 수 있습니다. 삭제된 레코드는 Lightning Platform에서 영구적으로 삭제되지 않지만 복원할 수 있는 위치에서 15일 동안 휴지통에 보관됩니다.

이 예는 성이 Smith인 모든 연락처를 삭제하는 방법을 보여줍니다. 대량 DML에 대한 샘플을 실행한 경우 조직에 이미 성이 Smith인 두 개의 연락처가 있어야 합니다. 익명 Apex를 사용하여 Developer Console에서 이 코드 조각을 실행한 다음 이름이 Smith인 연락처가 더 이상 없는지 확인합니다.

Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith'];
delete contactsDel;
참고

참고

이 코드 조각에는 연락처를 검색하는 쿼리(SOQL 쿼리)가 포함되어 있습니다. 다른 유닛에서 SOQL에 대해 자세히 살펴보겠습니다.

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 메서드

Apex에는 DML 작업을 수행하고 DML 문 대응 항목을 미러링하는 메서드를 제공하는 기본 제공 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);
참고

참고

upsert는 Database.UpsertResult 개체를 반환하고 delete는 Database.DeleteResult 개체를 반환합니다.

기본적으로 allOrNone 매개변수는 true로, 이는 Database 메서드가 DML 문과 동일하게 동작하고 오류가 발생할 경우 예외를 출력한다는 것을 의미합니다.

다음 두 가지 문은 insert recordList; 문과 같습니다.

Database.insert(recordList);

Database.insert(recordList, true);







참고

추가 기본 정보

이러한 메서드 외에도 Database 클래스에는 DML 문으로 제공되지 않는 메서드가 포함되어 있습니다. 예를 들어 트랜잭션 제어 및 롤백, 휴지통 비우기 및 SOQL 쿼리와 관련된 메서드에 사용됩니다. 다른 유닛에서 SOQL에 대해 알아보겠습니다.

예: 일부 성공한 레코드 삽입

Database 메서드를 사용하는 예를 살펴보겠습니다. 이 예제는 대량 DML 예제를 기반으로 하지만 DML 문을 Database 메서드로 대체합니다. Database.insert() 메서드는 일부 성공 옵션과 함께 호출됩니다. 목록의 한 연락처에는 의도적으로 필드가 없으며 필수 LastName 필드 없이 연락처를 저장할 수 없으므로 오류가 발생합니다. 세 개의 연락처가 커밋되고 필드가 없는 연락처는 오류를 생성합니다. 이 예제의 마지막 부분은 반환된 결과를 반복하고 디버그 메시지를 디버그 로그에 씁니다.

  1. 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());
    	 }
        }
    }
  2. 디버그 메시지를 확인합니다(필터에 DEBUG 키워드 사용).
    하나의 실패가 보고되어야 하고 세 개의 연락처가 삽입되어야 합니다.

DML 문 또는 Database 메서드를 사용해야 하나요?

  • 대량 DML 처리 중에 발생하는 오류가 제어 플로를 즉시 중단하는 Apex 예외로 출력되도록 하려면 DML 문을 사용합니다(try...catch 블록 사용). 이 동작은 대부분의 데이터베이스 절차 언어에서 예외가 처리되는 방식과 유사합니다.
  • 대량 DML 작업의 부분적인 성공을 허용하려면 Database 클래스 메서드를 사용하세요. 레코드가 실패하더라도 나머지 DML 작업은 계속 성공할 수 있습니다. 그러면 애플리케이션에서 거부된 레코드를 검사하고 작업을 재시도할 수 있습니다. 이 양식을 사용하면 DML 예외 오류가 발생하지 않는 코드를 작성할 수 있습니다. 대신 코드에서 적절한 결과 배열을 사용하여 성공 또는 실패를 판단할 수 있습니다. Database 메서드에는 DML 문과 유사하게 출력된 예외를 지원하는 구문도 포함되어 있습니다.

관계를 통해 서로 연결된 레코드를 만들고 관리합니다.

관련 레코드 삽입

조회 또는 마스터 - 세부 사항 관계와 같이 두 개체 간에 관계가 이미 정의된 경우 기존 레코드와 관련된 레코드를 삽입할 수 있습니다. 레코드는 외부 키 ID를 통해 관련 레코드와 연결됩니다. 예를 들어 새 연락처를 삽입하는 경우 AccountId 필드 값을 설정하여 연락처의 관련 계정 레코드를 지정할 수 있습니다.

이 예에서는 연락처의 AccountId 필드를 설정하여 계정(관련 레코드)에 연락처를 추가하는 방법을 보여줍니다. 연락처와 계정은 조회 관계를 통해 연결됩니다.

  1. Developer Console의 익명 Apex 창에서 이 코드 조각을 실행합니다.
    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;
  2. 조직의 연락처를 검사합니다.
    새 계정(SFDC 계정)을 만들었으며 계정의 연락처 관련 목록에 Mario Ruiz 연락처가 있습니다.

관련 레코드 업데이트

관련 레코드의 필드는 DML 작업에 대한 동일한 호출로 업데이트할 수 없으며 별도의 DML 호출이 필요합니다. 예를 들어 새 연락처를 삽입하는 경우 AccountId 필드 값을 설정하여 연락처의 관련 계정 레코드를 지정할 수 있습니다. 그러나 별도의 DML 호출로 계정 자체를 업데이트하지 않고는 계정 이름을 변경할 수 없습니다. 마찬가지로 연락처를 업데이트할 때 연락처의 관련된 계정도 업데이트하려면 DML 호출을 두 번 해야 합니다. 다음 예시에서는 두 가지 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;

관련 레코드 삭제

삭제 작업은 계단식 삭제를 지원합니다. 상위 개체를 삭제하면 각 하위 레코드를 삭제할 수 있는 한 자동으로 하위 개체를 삭제합니다.

예를 들어, 이전에 생성한 계정(SFDC 계정)을 삭제하면 관련 연락처도 삭제됩니다.

  1. Developer Console의 익명 Apex 창에서 이 코드 조각을 실행합니다.
    Account[] queriedAccounts = [SELECT Id FROM Account WHERE Name='SFDC Account'];
    delete queriedAccounts;
  2. 조직의 계정 및 연락처를 확인합니다.
    계정과 관련 연락처가 모두 삭제된 것을 확인할 수 있습니다.

트랜잭션 정보

DML 작업은 트랜잭션 내에서 실행됩니다. 트랜잭션의 모든 DML 작업은 성공적으로 완료되거나 한 작업에서 오류가 발생하면 전체 트랜잭션이 롤백되고 데이터베이스에 커밋된 데이터가 없습니다. 트랜잭션의 경계는 트리거, 클래스 메서드, 익명 코드 블록, Apex 페이지 또는 사용자 정의 웹 서비스 메서드가 될 수 있습니다. 예를 들어, 트리거 또는 클래스가 두 개의 계정을 만들고 하나의 연락처를 업데이트하고 유효성 검사 규칙 실패로 인해 연락처 업데이트가 실패하는 경우 전체 트랜잭션이 롤백되고 Salesforce에 계정이 유지되지 않습니다.

리소스

Salesforce 도움말에서 Trailhead 피드백을 공유하세요.

Trailhead에 관한 여러분의 의견에 귀 기울이겠습니다. 이제 Salesforce 도움말 사이트에서 언제든지 새로운 피드백 양식을 작성할 수 있습니다.

자세히 알아보기 의견 공유하기