Visualforce로 화면을 작성할 때, Visualforce 고유의 태그나 속성만을 이용해서는 구현하기 힘든 부분들이 있습니다.

예를 들면, 버튼 클릭 이벤트가 처리되기 이전에, 확인용 dialog를 표시한다던가, 체크 박스를 일괄 선택/해제 하는 기능 구현 한다던가 등등 이 있습니다.

 

이러한 경우, Javascript를 연동하면 추가적인 기능을 구현할 수 있습니다.

 

이번 포스팅에서는 간단히 Visualforce 개발 시, javascript를 연동하여 사용하는 방법에 대해서 설명하겠습니다.


# 목차

  • Javascript 함수 정의 방법

  • Visualforce 태그 내에서 Javascript 함수를 호출하는 방법

  • Javascript 함수 내에서 Apex 컨트롤러에 정의한 변수 및 함수 사용 방법

  • Javascript 사용 예시


# Javascript 함수 정의 방법

 

Visualforce 내에서 javascript 코드를 사용하는 방법은 <script type="text/javascript"> 태그 내부에 함수를 작성하는 것으로 사용할 수 있습니다.

 

<script type="text/javascript">
  // javascript methods 정의
</script>

 

또는 Visualforce 태그 내에서 직접적으로 정의하는 것도 가능합니다.

<apex:commandButton onclick="[JavaScript Code]"/>

# Visualforce 태그 내에서 Javascript 함수를 호출 하는 방법

 

정의한 javascript를 호출하기 위해서는 Visualforce의 각 태그의 속성 중, javascript 코드를 호출하는 onclick, oncomplete 등과 같은 속성에 지정하여 호출해야 합니다.

 

하지만, Visualforce의 모든 태그가 javascript 를 호출 할 수 있는 속성을 갖고 있는 것은 아니니, 항상 개발자 가이드를 확인하여 사용할 수 있는 속성을 파악하는 것이 중요합니다.

 

여기서는 <apex:commandButton> 태그를 예시로 사용하겠습니다. 

<apex:page>
    <script type="text/javascript">
        function jsMethod() {
            // javascript 코드
        }
    </script>

    <apex:form id="form">
        <!-- javascript 호출용 버튼 -->
        <apex:commandButton value="JS호출" onclick="jsMethod()"/>

        <!-- 아래의 방법으로도 javascript 코드 실행 가능 -->
        <!-- <apex:commandButton value="JS호출" onclick="[javascript 코드]"/> -->
    </apex:form >
</apex:page>

 

commandButton의 속성은 다음의 개발자 가이드를 확인해주세요.

Visualforce 개발자 가이드 - apex:commandButton


# Javascript 함수 내에서 Apex 컨트롤러에 정의한 변수 및 함수 사용 방법

 

Apex 컨트롤러에서 정의한 변수나 함수를 호출하기 위해서는, 먼저 각 변수와 함수의 정보를 Visualforce 내에 지정할 필요가 있습니다.

 

예시로 다음과 같은 Apex 컨트롤러 클래스가 있습니다.

/**
 * @description Visualforce Javascript 연동 페이지의 컨트롤러
 */
public with sharing class CntrlVfCallJs{

    /**
     * @description javascript에서 호출할 변수
     */
    public String myVariable { get; set; }

    /**
     * @description 생성자
     */
    public CntrlVfCallJs() {

        myVariable = 'Hello World';
    }

    /**
     * @description javascript에서 호출할 변수
     */
    public void myMethod() {

        // 화면에 메세지 표시
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Apex method called'));
    }
}

 

Visualforce에서 Apex의 변수와 메서드를 지정하는 방법은 다음과 같습니다.

    <!-- Apex 변수 지정 -->
    <apex:inputHidden id="myVar" value="{!myVariable}"/>
    
    <!-- Apex 메서드 지정 -->
    <apex:actionFunction name="myMthd" action="{!myMethod}"/>

 

위에서 지정한 Apex 변수와 메서드를 호출하는 방법은 다음의 샘플 코드와 같습니다.

<!-- Apex의 변수를 사용하기 위해 해당 Apex클래스를 "controller" 속성을 지정 -->
<apex:page controller="CntrlVfCallJs" sidebar="false">

  <script type="text/javascript">
    function callApexVarMethod() {
        // Visualforce에 지정한 Apex 변수를 javscript 내에서 습득(apex:inputHidden에 지정한 id 속성으로 대상을 지정)
        var myVar = document.getElementById('{!$Component.form.myVar}').value;
        // 역으로, Apex 변수의 내용을 변경하는 것도 가능
        // document.getElementById('{!$Component.form.myVar}').value = 'Bye World';

        // Apex 메서드 실행(apex:actionFunction에 지정한 name 속성으로 대상을 지정)
        myMthd();
    }
  </script>

  <apex:form id="form">
    <!-- 화면 메시지 표시란 -->
    <apex:pageMessages id="messagearea" showDetail="false"/>

    <!-- Apex 변수 지정 -->
    <apex:inputHidden id="myVar" value="{!myVariable}"/>
    <!-- Apex 메서드 지정 -->
    <apex:actionFunction name="myMthd" action="{!myMethod}"/>

    <apex:pageBlock title="Apex 변수 및 메서드 호출">
        <!-- 화면 메시지 표시란 -->
        <apex:pageMessages id="messagearea" showDetail="false"/>

        <apex:commandButton value="JS호출" oncomplete="callApexVarMethod()"/>
    </apex:pageBlock>
  </apex:form>
</apex:page>

 

☞ 버튼 클릭 결과 화면

 


# Javascript 사용 예시

 

 1. 실행 확인 dialog 표시 

 

<apex:page>
    <script type="text/javascript">
        function checkConfirm() {
            if(confirm('javascript 호출 테스트')){
                return true;
            }
            return false;
        }
    </script>

    <apex:form id="form">
        <!-- javascript 호출용 버튼 -->
        <apex:commandButton value="JS호출" onclick="checkConfirm()"/>

        <!-- 아래의 방법으로도 javascript 코드 실행 가능 -->
        <!-- <apex:commandButton value="JS호출" onclick="if(confirm('javascript 호출 테스트')){return true;}; return false;"/> -->
    </apex:form >
</apex:page>

 

☞ 버튼 클릭 결과 화면

 

 

 2. 체크박스 전체 선택/ 전체 해제 

 

Apex 컨트롤러 샘플

/**
 * @description javascript로 체크박스 전체 선택/해제 컨트롤러
 */
public with sharing class CntrlAllCheckByJs {

    /**
     * @description 체크 박스를 표시하기 위한 Wrapper 리스트
     */
    public List<MemberWrapper> memWrapperList { get; set; }

    /**
     * @description 체크박스를 표시하기 위한 Wrapper 클래스
     */
    private class MemberWrapper {

        public Boolean isSelected { get; set; }     // 체크 박스에 사용할 Boolean형
        public String memName { get; set; }         // 회원 이름
        // 개체 변수도 사용 가능
        // 예) public Member__c member { get; set; }

        /**
         * @description 생성자
         */
        public MemberWrapper() {

            isSelected = false;
        }
    }

    /**
     * @description 생성자
     */
    public CntrlAllCheckByJs() {

        memWrapperList = new List<MemberWrapper>();

        for (integer i = 0; i < 10; i++) {

            MemberWrapper memWrapper = new MemberWrapper();

            memWrapper.memName = '홍길동' + i;

            memWrapperList.add(memWrapper);
        }
    }
}

 

Visualforce 샘플

<apex:page controller="CntrlAllCheckByJs" sidebar="false">
    <script type="text/javascript">
        /**
         * @description 체크 박스의 전체 선택/해제
         */
        function checkAll(cb,cbid) {
            var inputElem = document.getElementsByTagName("input");

            for (var i =0 ; i < inputElem.length; i++) {
                if(inputElem[i].id.indexOf(cbid) != -1){
                    inputElem[i].checked = cb.checked;
                }
            }
        }
    </script>

    <apex:form id="form">
        <apex:pageBlock title="체크박스 전체 선택/해제">

            <!-- 리스트를 표 형식으로 출력 -->
            <apex:pageBlockTable value="{!memWrapperList}" var="member" style="width:10%;">

                <apex:column style="width:2%; text-align:center;">
                    <!-- 헤더 부분에 체크박스 추가 -->
                    <apex:facet name="header">
                        <apex:inputCheckbox id="checkAll" onclick="checkAll(this, 'selectRow')"/>
                    </apex:facet>
                    <!-- 데이터 부분에 체크박스 추가 -->
                    <apex:inputCheckbox id="selectRow" value="{!member.isSelected}"/>
                </apex:column>

                <apex:column value="{!member.memName}" headerValue="회원 이름" style="width:8%;"/>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

 

☞ 결과 화면

 

 

 2-1. 체크 박스로 선택한 요소의 정보 습득 

 

2의 코드에서 다음 메서드와 버튼을 추가

 

Apex 컨트롤러 샘플(추가)

    /**
     * @description 체크 박스로 선택된 회원의 회원명 습득
     */
    public void getSelectedItem() {

        List<String> selMembersNameList = new List<String>();

        for (MemberWrapper memWrap : memWrapperList) {

            if (memWrap.isSelected) {
                // 체크 박스가 선택된 경우

                selMembersNameList.add(memWrap.memName);
            }
        }

        System.debug('선택된 멤버명 ' + selMembersNameList);
    }

 

Visualforce 샘플(추가)

<apex:pageBlock title="체크박스 전체 선택/해제">

            <apex:pageBlockButtons location="top">
                <apex:commandButton id="btnGetSelItems" value="선택" action="{!getSelectedItem}"/>
            </apex:pageBlockButtons>

            <!-- 리스트를 표 형식으로 출력 -->
---- 생략 ----

 

☞ 결과 화면

 

 

 3. 링크로 선택한 요소의 정보 습득 

  ※ 코드는 2에서 작성한 코드에 추가 기능을 추가하는 방법으로 구현하겠습니다.

 

Apex 컨트롤러 샘플(추가)

/**
 * @description "선택" 링크로 선택된 회원명
 */
public String selMemberName { get; set; }

---- 생략 -----

/**
 * @description "선택" 링크로 선택된 회원의 회원명 습득
 */
public void getMemberNameByLink() {

    System.debug('선택된 멤버명 : ' + selMemberName);
}

 

Visualforce 샘플(추가)

<script type="text/javascript">
    /**
     * @description "선택" 링크로 선택한 회원 정보 습득
     */
    function selectMember(mName) {
        document.getElementById('{!$Component.form.selMemName}').value = mName;

        getMemNameByLink();
    }
</script>

<apex:form id="form">
    <apex:inputHidden id="selMemName" value="{!selMemberName}"/>

    <apex:actionFunction name="getMemNameByLink" action="{!getMemberNameByLink}"/>

----- 생략 -----

<apex:column style="width:3%;">
    <apex:facet name="header">선택</apex:facet>
    <apex:commandLink id="selectLink" value="선택" onclick="selectMember('{!member.memName}');"/>
</apex:column>

 

전체 샘플 코드는 아래의 링크에서 확인하실 수 있습니다.

github.com/mokochi/Blog_SFDC_UseJavaScriptInVisualforce.git

 


이상으로 Visualforce 내에서 javascript를 연동하여 사용하는 방법에 대해 알아보았습니다.

 

이 포스트의 사용 예시 이외에도 화면 전환, 팝업 표시, pdf화면 표시 등

여러 방면에서 javascript를 필연적으로 사용해야만 하는 상황이 자주 발생하니,

이 부분은 개발자 가이드를 통해 확실하게 익혀두는 것이 중요합니다.

 

추가로 이곳에서는 사용하지 않았지만, Visualforce 내에서 ajax 나 jQuery도 사용 가능합니다.

 

 

 

 

참고) https://developer.salesforce.com/docs/atlas.en-us.226.0.pages.meta/pages/pages_javascript_intro.htm - Visualforce 개발자 가이드 - Using JavaScript in Visualforce Page

Salesforce로 개발을 하기 위해 기능 설계를 하는 단계에서, 무엇보다도 가장 중요하고 고려해 보아야 할 것 중 하나가 Salesforce의 Governor Limits라는 것입니다.

 

대량의 데이터를 처리해야 하는 기능을 개발하는 단계에 있어, 이 제한이 가장 짜증나는 부분이며 예상치 못하고 있다간, 이 제한으로 인해 로직을 변경해야 하는 일이 발생합니다.

 

이번 포스팅에서는 Gorvernor Limits에 대해 설명하겠습니다.


# 목차

  • Governor Limits 란?

  • 남은 제한 확인 방법

  • 회피 방법 예시


 

# Governor Limits 란?

Gorvernor Limits이란, 멀티 테넌트 환경에서 실행하기 위해, Apex 런타임 엔진이 Apex 코드 또는 프로세스가 공유 자원을 독점하지 못하도록 강제로 제한하는 것을 말합니다.

즉, Salesforce 측에서 지나친 독점을 막기 위해 지정해 둔 제한이라고 할 수 있습니다.

(물론, 라이센스 단계에 따라 한계치가 바뀌기도 합니다.)

 

Salesforce의 거의 모든 부분에 있어서 이 제한이 걸려있다고 할 수 있기 때문에, 설계나 개발 단계에서 항상 고려해야 하는 부분입니다.

 ex) 개체 등록 가능 수, 레코드 등록 가능 수, 1트랜잭션 에서 SELECT 가능한 데이터 수, Apex 클래스 등록 가능수, Apex 코드 문자수 등등

 

Gorvernor Limits에 대한 상세내용은 다음을 참고해주세요.

Salesforce Developer Guide - Apex Governor Limits

Salesforce Developer Guide - Execution Governors and Limits


 

# 남은 제한 확인 방법

Apex에는 Gorvernor Limits을 확인하기 위한 "Limits" 클래스가 존재합니다.

 

Limits 클래스에 대한 상세내용은 다음을 참고해주세요.

Salesforce Developer Guide - Limits

 

Apex 코드 상에서는 이 Limit을 통해 남아 있는 제한 수를 확인하는 것이 가능합니다.가끔 확인을 위해 SOQL 쿼리의 실행 수나 스텝 수를 확인하는 메소드를 주로 사용했지만, 이 외에도 여러가지로 많았기 때문에 전부 확인해 보았습니다.ex) 샘플 코드

System.debug('limits.getAggregateQueries()                 = ' + limits.getAggregateQueries());                     // SOQL 쿼리 문이 처리 된 집계 쿼리의 수
System.debug('limits.getLimitAggregateQueries()            = ' + limits.getLimitAggregateQueries());                // SOQL 쿼리 문에서 처리 할 수 있는 집계 쿼리의 총 수
System.debug('limits.getCallouts()                         = ' + limits.getCallouts());                             // 처리 된 Web 서비스의 수
System.debug('limits.getLimitCallouts()                    = ' + limits.getLimitCallouts());                        // 처리 할 수있는 Web 서비스의 총 수
System.debug('limits.getCpuTime()                          = ' + limits.getCpuTime());                              // 현재의 트랜잭션에서 사용 된 Salesforce 서버의 CPU 시간 (밀리 초)
System.debug('limits.getLimitCpuTime()                     = ' + limits.getLimitCpuTime());                         // 트랜잭션에서 사용 가능한 최대 CPU 시간 (밀리 초)
System.debug('limits.getDMLRows()                          = ' + limits.getDMLRows());                              // DML 제한에 포함되는 모든 문을 사용하여 처리 된 레코드의 수
System.debug('limits.getLimitDMLRows()                     = ' + limits.getLimitDMLRows());                         // DML 제한에 포함되는 모든 문을 사용하여 처리 할 수있는 총 레코드 수
System.debug('limits.getDMLStatements()                    = ' + limits.getDMLStatements());                        // 호출 된 DML 문 (insert,update또는 database.EmptyRecycleBin 메소드 등)의 수
System.debug('limits.getLimitDMLStatements()               = ' + limits.getLimitDMLStatements());                   // 호출 할 수있는 DML 문 또는database.EmptyRecycleBin 메소드의 총 수
System.debug('limits.getEmailInvocations()                 = ' + limits.getEmailInvocations());                     // 호출 된 메일 호출 수(sendEmail 등) 
System.debug('limits.getLimitEmailInvocations()            = ' + limits.getLimitEmailInvocations());                // 호출 할 수있는 메일 호출의 총 개수(sendEmail 등)
System.debug('limits.getFindSimilarCalls()                 = ' + limits.getFindSimilarCalls());                     // getSoslQueries 같은 값을 반환
System.debug('limits.getLimitFindSimilarCalls()            = ' + limits.getLimitFindSimilarCalls());                // getLimitSoslQueries 같은 값을 반환
System.debug('limits.getFutureCalls()                      = ' + limits.getFutureCalls());                          // 실행 된 future 주석이 있는 메소드의 수
System.debug('limits.getLimitFutureCalls()                 = ' + limits.getLimitFutureCalls());                     // 실행할 수 future 주석이 있는 메소드의 총 개수
System.debug('limits.getHeapSize()                         = ' + limits.getHeapSize());                             // 힙에 사용 된 메모리의 대략의 용량 (Byte 단위)
System.debug('limits.getLimitHeapSize()                    = ' + limits.getLimitHeapSize());                        // 힙을 사용할 수 있는 메모리의 총 용량 (Byte 단위)
System.debug('limits.getLimitMobilePushApexCalls()         = ' + limits.getLimitMobilePushApexCalls());             // 모바일 푸시 알림으로 1 트랜잭션 당 허용되는 Apex 총 통화 수
System.debug('limits.getQueries()                          = ' + limits.getQueries());                              // 발행 된 SOQL 쿼리의 수
System.debug('limits.getLimitQueries()                     = ' + limits.getLimitQueries());                         // 발급 할 SOQL 쿼리의 총 수
System.debug('limits.getQueryLocatorRows()                 = ' + limits.getQueryLocatorRows());                     // Database.getQueryLocator 메소드에서 반환 된 레코드 수
System.debug('limits.getLimitQueryLocatorRows()            = ' + limits.getLimitQueryLocatorRows());                // Database.getQueryLocator 메소드에서 반환 할 수있는 총 레코드 수
System.debug('limits.getQueryRows()                        = ' + limits.getQueryRows());                            // SOQL 쿼리의 발행에서 반환 된 레코드 수
System.debug('limits.getLimitQueryRows()                   = ' + limits.getLimitQueryRows());                       // SOQL 쿼리의 발행에 반환 할 수있는 총 레코드 수
System.debug('limits.getQueueableJobs()                    = ' + limits.getQueueableJobs());                        // 트랜잭션마다 추가된 큐 중,  큐 처리가 가능한 작업 수
System.debug('limits.getLimitQueueableJobs()               = ' + limits.getLimitQueueableJobs());                   // 트랜잭션마다 추가된 큐 중,  큐 처리가 가능한 작업의 최대수
System.debug('limits.getRunAs()                            = ' + limits.getRunAs());                                // getDMLStatements 같은 값을 반환
System.debug('limits.getLimitRunAs()                       = ' + limits.getLimitRunAs());                           // getLimitDMLStatements 같은 값을 반환
System.debug('limits.getSavepointRollbacks()               = ' + limits.getSavepointRollbacks());                   // getDMLStatements 같은 값을 반환
System.debug('limits.getLimitSavepointRollbacks()          = ' + limits.getLimitSavepointRollbacks());              // getLimitDMLStatements 같은 값을 반환
System.debug('limits.getSavepoints()                       = ' + limits.getSavepoints());                           // getDMLStatements 같은 값을 반환
System.debug('limits.getLimitSavepoints()                  = ' + limits.getLimitSavepoints());                      // getLimitDMLStatements 같은 값을 반환
System.debug('limits.getSoslQueries()                      = ' + limits.getSoslQueries());                          // 발행 된 SOSL 쿼리의 수
System.debug('limits.getLimitSoslQueries()                 = ' + limits.getLimitSoslQueries());                     // 발급 할 SOSL 쿼리의 총 수
//System.debug('limits.getAggregateQueries()                 = ' + limits.getChildRelationshipsDescribes());          // 반환 된 자식 관계 개체의 수

 

☞실행 결과

 

Apex 코드 내에서 확인하는 방법 이외에, "Workbench" 라는 사이트를 통해서 확인하는 방법도 있습니다.

 

Workbench(워크 벤치)를 이용해서 확인하는 방법은 다음과 같습니다.

먼저 확인 대상이 되는 환경에 로그인 하기 위해, [I agree to the terms of service]에 체크하고 [Login with Salesforce] 버튼을 눌러 로그인을 합니다.

로그인 화면 표시

 

로그인 허용, 환경 로그인

환경에 로그인이 되었다면, [Utilities - REST Explorer]를 선택해주세요.

그 후 표시되는 REST Explorer 화면에서, "/services/data/v48.0/limits" 를 입력하고 [Execute] 버튼을 누르면 현재 사용 가능한 Gorvernor Limits의 수가 종류별로 표시가 됩니다.


 

# 회피 방법 예시

 

Apex 개발을 하다보면, 데이터 처리 등에 있어 Gorvernor Limits이 걸리는 경우, 제한이 걸리지 않게 하기 위해 로직을 변경하여 회피해야 합니다.

 

이번 예시에서는 작성자 본인이 평소 일을 하면서 자주 사용하는 회피 방법 3가지에 대해 설명하겠습니다.

( 혹시 고수분들 중에, 더 나은 방법이라 생각되는 것이 있으시다면 알려주시기 바랍니다. (_o_) )

 

1. Batch를 통한 일괄 처리 방법 

Apex에서는 다량의 데이터(수천~수백만 개의 데이터)를 처리하기 위해, "Database.Batchable" 이라는 인터페이스를 제공하고 있습니다.

이 Batch를 사용하면 해당 플랫폼의 제한을 초과하지 않고, 레코드를 Batch 단위로 나누어, 비동기로 일괄 처리할 수 있습니다. 

그렇기 때문에, 데이터의 정리 및 보관 등, 처리해야 하는 레코드의 수가 많을 경우, Batch를 통한 일괄 처리가 적합합니다.

Apex Batch를 통한 일괄 처리 가이드

Salesforce Trailhead - Apex 일괄처리(Batch)

 

"Database.Batchable" 인터페이스는 다음과 같이 구성되어 있습니다.

global class MyBatchClass implements Database.Batchable<sObject> {
    global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {
        // execute에 전달하여 일괄 처리할 레코드를 습득
        // 주로, Database.QueryLocator를 통해 레코드 습득
        // QueryLocator를 사용하는 경우 Gorvernor Limits "SOQL 쿼리로 검색된 레코드의 총 개수"가 무시되고 최대 5,000만 레코드까지 조회가능
        // Iterable를 사용하는 경우 Gorvernor Limits "SOQL 쿼리로 검색된 레코드의 총 개수"가 그대로 적용
    }

    global void execute(Database.BatchableContext bc, List<P> records){
        // start로 부터 전달 된 레코드 일괄 처리
        // 기본 Batch 크기는 200 레코드
        // 레코드 배치가 start 메소드로부터 받은 순서대로 실행된다는 보장이 없음
    }

    global void finish(Database.BatchableContext bc){
        // 레코드 일괄 처리 실행 후 처리할 마무리 작업(이메일 전송 등)
        // 모든 배치가 처리 된 후 1회만 호출
    }
}

 

즉, 그림으로 표현하면 아래와 같이 됩니다.

Batch 실행도 

 

Database.Batchable의 사용 예시는 다음과 같습니다.

/**
 * @description 회원명 갱신 Batch
 */
global class UpdateMemberName implements Database.Batchable<sObject>, Database.Stateful {

    /**
     * @description 일괄 처리 대상 레코드 SELECT
     */
    global Database.QueryLocator start(Database.BatchableContext bc) {

        // 회원 레코드 SELECT, return으로 execute에 레코드 전달
        return Database.getQueryLocator(
            'SELECT '
            + ' ID '
            + ', Name '
            + 'FROM '
            + ' Member__c '
        );
    }

    /**
     * @description 레코드 일괄 처리 메서드(비동기)
     */
    global void execute(Database.BatchableContext bc, List<Member__c> memberList){
        
        for (Member__c member : memberList) {

            // 회원 이름 뒤에 "님" 추가
            member.Name = member.Name + ' 님 ';
        }

        // 회원 레코드 UPDATE
        update memberList;
    }    
    global void finish(Database.BatchableContext bc){

        // 현재 처리중인 Batch 의 Job 정보 표시(단순 확인용)
        AsyncApexJob job = [SELECT Id, Status, NumberOfErrors, 
            JobItemsProcessed,
            TotalJobItems, CreatedBy.Email
            FROM AsyncApexJob
            WHERE Id = :bc.getJobId()];
        System.debug(job);

        // execute 일괄 처리 이후의 회원 정보 확인
        List<Member__c> memberList = [SELECT Id, Name FROM Member__c];
        System.debug(memberList); 
    }    
}

 

Batch 클래스를 작성하였다면, 작성한 Batch를 실행해보겠습니다.

지금은 개발자 콘솔에서 실행하겠습니다만, 실제 개발에서는 Apex 코드 내에서 실행하시면 되겠습니다.

 

[개발자 콘솔 - Open Execute Anonymous Window]로 Apex 코드 입력창을 표시합니다.

그 후, 아래의 코드를 작성한 후 [Execute]버튼을 눌러 Batch를 실행합니다.

// 실행 대상 Batch 클래스 정의
UpdateMemberName umnBatch = new UpdateMemberName(); 

// Database.executeBatch를 통해 Batch 실행
// prm1 : 실행 대상 Batch
// prm2 : 1개의 Batch 내에서의 일괄 처리 레코드 수
Id batchId = Database.executeBatch(umnBatch, 200);

 

2. 1개의 트랜잭션에서 실행 가능한 SOQL 제한을 회피하는 방법

Gorvernor Limits 가이드를 보셨다면 아마 아시겠지만, 1개의 트랜잭션에서 실행 가능한 SOQL의 쿼리 수에 제한이 있습니다.

즉, 가능한 반복문에서는 SOQL 쿼리를 사용하지 않는 것이 중요하다는 의미가 됩니다.

 

혹시, 반복문 내에서 다른 데이터의 정보를 습득해서 수정하는 처리 등을 해야할 필요가 있을 경우에는 로직을 통해 회피하는 수 밖에 없습니다.

 

여기서는 주로 제가 사용하는 방법에 대해 설명하겠습니다.

(아마 경험 많은 개발자 분들이면 충분히 사용하고 있을 법한 로직이 되겠습니다만..)

 

간단히 설명하면 다음과 같은 방법이 되겠습니다.

  ① 반복문에 들어가기 이전에 필요로 하는 레코드를 전부 SELECT 해서 Map에 저장

    ※ 여기서도 1개의 SOQL 쿼리로 SELECT 가능한 Gorvernor Limits(50,000개)이 있기 떄문에, 필요에 따라 WHERE로 필요한 레코드만 SELECT

  ② 반복문에서는 그 Map으로부터 데이터를 습득해서 사용

 

그럼 샘플 코드로 확인해보겠습니다.

/**
 * @description 도서 대여중인 회원의 이름
 */
private void getMemberNameByBookLender() {

    // 모든 회원을 SELECT해서 Map에 추가 (Key:레코드ID, Value: 회원 개체)
    Map<ID, Member__c> allMemberMap = (Map<ID, Member__c>)[SELECT Id, Name FROM Member__c];
    List<Book__c> allBookList = [SELECT Id, Name, Lender__c FROM Book__c];

    for (Book__c book : allBookList) {

        if (String.isBlank(book.Lender__c) || allMemberMap.containsKey(book.Lender__c)) {
            // 도서가 대여중이 아닌 경우 또는 대여 중인 회원 정보를 찾지 못한 경우, 다음 도서로 넘어감

            continue;
        }

        // 회원Map에서 회원ID가 일치하는 회원 정보를 검색
        Member__c lender = allMemberMap.get(book.Lender__c);

        System.debug('도서명 : ' + book.Name + ' 대여 중인 회원명 : ' + lender.Name);
    }
}

 

이러한 형식으로 반복문에서 SOQL 쿼리를 사용하지 않고도 필요한 데이터를 습득하고 사용할 수 있습니다.

특히, Map을 잘 사용할 수 있도록 익혀두면, 여러 방면에서 유용하게 사용할 수 있습니다.

 

3. 1개 컬렉션으로 표시 가능한 데이터 제한 수

어떻게 보면, Gorvernor Limits으로 인해 가장 짜증나는 경우가 이 경우일 수 있습니다.

Gorvernor Limits 중, 1개의 컬렉션에서 표시 가능한 데이터 수가 있는데 쉽게 말하면, 

검색 화면에서 데이터를 검색했을 때, 검색 결과가 제한 수인 1000개 이상이 되면 에러가 발생한다는 것입니다.

 

 

이 부분에 대해서는 딱히 1000개 이상을 표시하기 위한 회피 방법이 없으므로, 로직상에서 1000개 이하가 되도록 데이터에 제한을 걸고, 화면에 INFO 메시지로 "최대 표시 가능한 데이터 수를 초과했으므로, 선두 1000개만 표시합니다." 라던가, "검색 조건을 통해 결과를 좁혀주세요." 라는 등의 방법을 사용하고 있습니다.

( 좋은 방법 있으면 알려주시면 감사하겠습니다. )

 

샘플 코드

final integer VF_COLLECTION_ITEM_LIMIT = 1000;
if (VF_COLLECTION_ITEM_LIMIT < memberList.size()) {
    // 검색 결과가 1개 컬렉션에서 표시 가능한 데이터 제한수(1000개)를 초과한 경우

    // 화면에 메시지 표시
    ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, '표시 가능한 데이터 수 초과, 검색 조건을 지정해 대상을 좁히시오.'));

    while (VF_COLLECTION_ITEM_LIMIT < memberList.size()) {

        // 제한 수에 도달할 때 까지, 맨 뒤의 요소를 삭제
        memberList.remove(memberList.size() - 1);
    }
}

 

이 외에 가장 큰 문제가 되는 부분이 바로 csv출력 입니다.

csv를 출력할 때에도 출력에 사용되는 컬렉션에 1000개 이상의 데이터가 있는 경우, 위와 동일한 에러가 발생하게 됩니다.

 

작성자의 경우, 이 문제에 대해서는 정적으로 2개 이상의 컬렉션를 정의 해놓은 다음, 각각의 컬렉션을 순서대로 출력하는 방법을 사용하고 있습니다.

허나, 이 방법을 사용할 때의 문제점으로는 각 컬렉션에 분할에서 넣기 위한 로직이 필요하다는 것입니다.

( 이 부분에 대해서도 좋은 방법 있으면 공유 해주시면 감사하겠습니다. )


 

이것으로, Salesforce로 개발을 할 때에 가장 신경써야 하는 부분 중 하나인 Gorvernor Limits에 대해 알아보았습니다.

 

개인적으로 이 Gorvernor Limits 때문에 Salesforce를 때려치고 싶다는 생각이 들 정도로 개발을 하다보면 상당히 불편한 부분입니다.

그렇기 때문에, 설계 단계에서 우선적으로 조사한 후, 거기에 맞춰서 설계를 해놓을 필요가 있습니다.

 

 

 

 

 

 

 

참고1) https://trailhead.salesforce.com/ja/content/learn/modules/asynchronous_apex/async_apex_batch - Apex Batch 일괄 처리

참고2) developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_limits.htm - Limits Class

참고3) https://mokochi.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts - Governor Limits

# 목차

  • Sobject 란?

  • Apex, Visualforce, Lightning Component

  • 개발자 콘솔(Developer Console)

  • Generate & Analyze logs

  • SOQL & SOSL Query

  • DML Statement & Database Method


# SObject 란?

 : Salesforce의 개체를 선언하는 생성자

 : SObject와 Field는 "API 이름" 으로 호출

 : SObject는 모든 개체를 상속 받을 수 있다. 즉, 다른 언어에서의 Object와 비슷하지만, 개체만을 위한 Object형 이라고 생각하면 쉽다.

 ex)

SObject sobj = new Book__c(Name = '원피스 1권');       ( O )
SObject sobj = '문자열';      ( X )
List<SObject> sobjList = { new Book__c(Name = '원피스 1권'), new Member__c(Name = '홍길동') };  ( O )

 

형변환(Type Casting)

서로 다른 개체끼리형변환이 불가능하지만, SObject는 각각의 개체로 형변환이 가능하다.

ex)

// 서로 다른 개체끼리의 형변환은 불가능
Member__c member = new Book__c(Name = '원피스 1권');   ( ERROR )
Member__c member = (Member__c)book;   ( ERROR )

// SObejct의 형변환은 가능
SObject sobj = new Member__c(Name = '홍길동');   ( O )
Member__c member = (Member__c)sobj;   ( O )
String memName = ((Member__c)sobj).Name;   ( O )

단, SObject에서는 점 표기법을 사용한 직접적인 필드 접근이 불가능하다.(SObject.Id만 접근 가능)

 => get(), set() 메서드를 통한 접근 또는 형변환 이후 접근 가능

ex)

SObject sobj = new Member__c(Name = '홍길동');

ID memId = sobj.Id;   ( O )
String memName = sobj.Name;   ( ERROR )
String memName = ((Member__c)sobj).Name;   ( O )

 

# Apex, Visualforce, Lightning Component

1. Apex 란?

 : 조직의 비즈니스 프로세스를 사용자 정의하는 데에 사용되는 Salesforce 자체 개발 언어

 : Java를 토대로 만들어 졌으며, 조직의 데이터와 상호 작용하는 언어

 : Lightning Platform API에 대한 호출, Lightning Platform 서버에서 Flow 및 Transaction 제어문을 실행할 수 있도록 유형화된 객체 지향 언어를 호출 할 수 있음

 

2. Visualforce 란?

 : 모바일 및 데스크톱 앱의 사용자 인터페이스를 구축하기 위한 웹 개발 프레임워크

 : 페이지 위주의 개발

 

3. Lightning Component

 : 모바일 및 데스크톱 앱을 개발하기 위한 프레임워크

 : 앱의 탭, 페이지, 레코드 페이지, 커뮤니티 페이지 등을 구성하는 옵션 결정 가능

 

※ Visualforce 와 Lightning Component의 차이

 1) Visualforce는 페이지 중심

 2) 레코드 저장 시, Visualforce 페이지는 서버와 상호작용을 하고, 사용자 인터페이스를 Reload

 3) Lightning Component는 서버보다 단말(Device)에서 더 많은 작업을 한다.

  참고) Lightning Experience Development - Lightning Experience 개발 가이드


 

# 개발자 콘솔(Developer Console)

 : 앱 개발, 디버그 및 테스트를 할 수 있도록 Salesforce 브라우저 상에서 제공되는 통합 개발 환경(IDE)

  현재 로그인 중인 하나의 조직에만 연결되는 브라우저 기반의 IDE이기 때문에,

  복수의 조직에 연결하거나 파일 비교, 동기화, 버전 제어 및 관리 등을 하기 위해서는 Force.com IDE(ex. Eclipse, Visual Studio Code)를 사용

  ※ Eclipse의 경우, 2019년 10월 부터 지원이 중지되었기 때문에 요즘에는 주로 Visual Studio Code(이하 VSCode)를 많이 사용합니다.

 

VSCode 개발 환경 구축 방법

2020/07/25 - [Salesforce.com/SFDC Memo] - [SFDC] Visual Studio Code에서 Force.com 개발 환경 구축하기

 

 

☞ 개발자 콘솔 여는 방법


 

# Generate & Analyze Logs

 : 대체적으로, Salesforce 개발 중에 발생하는 에러 등, 로그 확인 및 디버깅은 개발자 콘솔에서 이루어진다.

 

컴파일 에러가 발생했 을 경우, 에러 메시지를 포함한 dialog box 가 표시된다.

상세 내용은, [Logs]탭에 표시되는 로그를 더블 클릭 해서 상세 로그를 표시할 수 있다.

 

[Debug > View Log Panels]로 현재 표시중인 로그를 다양한 패널 뷰로 표시할 수 있다.

  • [Stack Tree] : 하향식 트리보기를 통해 객체의 계층 구조 및 실행 내의 로그 항목 표시

  • [Execution Stack] : 선택한 항목의 상향식 보기를 표시, 로그 항목을 표시

  • [Execution Log] : 코드를 실행하는 동안 발생한 모든 작업을 표시

  • [Source] : 소스 파일의 내용을 표시, 선택한 로그 항목이 생성될 때 실행되는 코드를 표시

  • [Source List] : 이벤트가 기록될 때 실행중인 코드의 컨텍스트를 표시

  • [Variables] : 선택한 로그 항목을 생성한 코드가 실행될 때 범위에 있었던 변수와 할당된 값을 표시

  • [Execution Overview] : 실행 시간 및 힙의 크기를 포함하여 실행 중인 코드의 통계를 표시

 

Apex 코드 내에서 CheckPoint(Break point)를 지정하여 특정 지점에서 일어나고 있는 상태를 볼 수 있다.

Checkpoint는 Apex Code 왼쪽의 코드 라인을 클릭해서 지정할 수 있다.

Checkpoint 지정

 

Checkpoint의 확인은 개발자 콘솔의 [Checkpoints] 탭에서 확인 가능합니다.

 

Apex 코드 내에서의 Debug log 표시하는 방법은 아래의 코드를 사용한다.

System.debug(msg);

 

또한, 개발자 코드의 로그에서 [Debug only]를 체크하면 Apex 코드 내에서 지정한 로그만을 표시하는 것이 가능하다.


 

# SOQL & SOSL Query

 

1. SOQL 이란?

 : Salesforce Object Query Language의 약자

 : SOQL을 사용하여 데이터베이스(개체)에 저장된 정보를 읽을 수 있음

 : SQL(Structured Query Language)와 유사

 

ex)

// 이름이 홍길동인 회원의 개체ID와 회원명을 검색
SELECT Id, Name FROM Member__c WHERE Name = '홍길동'

 

[개발자 콘솔 - Query Editor]에서 Query 실행 방법

 

Apex 코드 내에서의 코드 실행 방법

// Apex 코드내에서의 SOQL Qeury 실행
// 대체적으로 List<>형식으로 습득
List<Member__c> memberList = [SELECT Id, Name FROM Member__c WHERE Name = '홍길동'];

// 특정키를 통해 단일 개체로도 습득 가능
Member__c member1 = [SELECT Id, Name FROM Member__c WHERE Id = '[대상의 개체Id]'];

// WHERE구 등에서 변수를 사용하는 방법
// 변수의 앞에 "콜론(:)"을 붙여서 변수임을 알림
ID memberId = memberList.get(0).Id;
Member__c member2 = [SELECT Id, Name FROM Member__c WHERE Id = :memberId];

 

2. SOSL 이란?

 : Salesforce Object Search Language의 약자

 : 레코드에서 텍스트 검색을 수행하는 언어

 : SOQL과 달리, 여러 유형의 개체를 동시에 쿼리할 수 있음

 : SOQL은 정확한 구문을 필요로 하지만, SOSL은 단어 일치를 사용하여 필드를 검색할 수 있음.

ex) 회원명이 "꼬비" 인 회원 레코드와, "꼬비"회원이 대여중인 도서의 개체ID, 도서명 검색

FIND {꼬비} IN ALL FIELDS RETURNING Book__c(Id, Name), Member__c(Id, Name)

 

[개발자 콘솔 - Query Editor]에서 Query 실행 방법

 

Apex 코드 내에서의 코드 실행 방법

// SOSL 검색
List<List<SObject>> soqlResultList = [FIND '꼬비' IN ALL FIELDS RETURNING Book__c(Id, Name), Member__c(Id, Name)];

// SOSL 검색 결과로 부터 각 개체 정보 습득
List<Book__c> bookList = soqlResultList.get(0);
List<Member__c> memberList = soqlResultList.get(1);

// 각 검색 결과 확인
System.debug('도서명 : ' + bookList.get(0).Name);
System.debug('회원명 : ' + memberList.get(0).Name);

# DML Statement & Database Method

1. DML Statement

 : 단일 개체 또는 개체 리스트를 허용

 : Salesforce에는 INSERT, UPDATE, DELETE, UPSERT(특수DML) 이 존재

  ※ UPSERT : INSERT와 UPDATE가 합쳐진 DML로, 지정된 필드를 사용해 기존 개체의 존재 여부를 결정하거나 필드가 지정되지 않은 경우, ID를 통해 개체 레코드를 INSERT 또는 UPDATE한다.

    (기존 레코드가 없는 경우 => INSERT, 기존 레코드가 존재하는 경우 => UPDATE)

// 단일 레코드 INSERT
Member__c insMember = new Member__c(Name = '홍길동');
insert insMember;

// 다수 레코드 INSERT
List<Member__c> insMemberList = new List<Member__c>();
insMemberList.add(new Member__c(Name = '홍길동1'));
insMemberList.add(new Member__c(Name = '홍길동2'));
insMemberList.add(new Member__c(Name = '홍길동3'));
insert insMemberList;

// 단일 레코드 UPDATE
Member__c updMember = new Member__c(Id = insMember.Id, Name='고길동');
update updMember;

// 다수 레코드 UPDATE
List<Member__c> updMemberList = new List<Member__c>();
updMemberList.add(new Member__c(Id = insMemberList.get(0).Id, Name = '고길동1'));
updMemberList.add(new Member__c(Id = insMemberList.get(1).Id, Name = '고길동2'));
updMemberList.add(new Member__c(Id = insMemberList.get(2).Id, Name = '고길동3'));
update updMemberList;

// 단일 레코드 DELETE
delete insMember;

// 다수 레코드 DELETE
delete insMemberList;

// 단일 레코드 UPSERT
Member__c upsMemberIns = new Member__c(Name = '고길동');
Member__c upsMemberUpd = new Member__c(Id = insMember.Id, Name='고길동');
upsert upsMemberIns;   // UPSERT에 의한 INSERT
upsert upsMemberUpd;   // UPDATE에 의한 UPDATE

// 다수 레코드 UPSERT
List<Member__c> upsMemberList = new List<Member__c>();
upsMemberList.add(new Member__c(Name = '고길동'));
upsMemberList.add(new Member__c(Id = insMember.Id, Name = '고길동'));
upsert upsMemberList;  // 첫번째 요소는 INSERT, 두번째 요소는 UPDATE

 

2. Database Method

 : 정적 메소드(static)이므로 클래스명 및 메소드 명(Database.[메소드명])으로 호출(Salesforce의 표준 라이브러리)

 : DML작업을 부분적으로 성공시킬지에 대한 여부 설정 가능(allOrNone : Boolean)

  • [allOrNone = true]인 경우(Default), 전체 성공을 기준으로 함

  • [allOrNone = false]인 경우, 성공한 레코드는 데이터베이스에 commit, 실패한 레코드에러가 반환(예외 발생 X) 

 : Database Method는 DML처리 결과(성공 여부)를 배열로 반환해 준다.

// param1) INSERT할 개체 리스트(또는 단일 개체)
// param2) allOrNone
Database.SaveResult[] results = Database.insert([INSERT 개체리스트], false);

 

ex)

List<Member__c> insMemList = new List<Member__c>();
insMemList.add(new Member__c(Name = '홍길동'));
insMemList.add(new Member__c(Name = '고길동'));

// 회원 리스트 INSERT
Database.SaveResult[] srList = Database.insert(insMemList, false);

// DML처리 결과 확인
for (Database.SaveResult sr : srList) {

    // INSERT 성공여부 체크(isSuccess())
    if (sr.isSuccess()) { 
        // INSERT 성공

        System.debug('INSERT 성공 회원의 개체ID : ' + sr.getId());

    } else {
        // INSERT 실패

        for (Database.Error err : sr.getErrors()) {

            // ERROR메시지 표시
            System.debug(err.getStatusCode() + ' : ' + err.getMessage());
            System.debug('실패 레코드 정보 : ' + err.getFields());
        }
    }    
}

 

DML Statement 와 Database Method 사용

 : DML Statement는 예외처리(try-catch)를 통해 즉시 DmlException을 발생, 중단시키는 경우에 사용

 : Database Method는 DmlException을 무시하는 경우, 즉, DML 처리 결과에 상관없이, 일단 전부 실행한 뒤, 실패한 요소에 대해서만 따로 처리하는 경우

   (물론, Database Method에서도 Exception을 발생 시킬 수 있다.)

 

 

 

 

 

 

참고1) https://developer-cj.tistory.com/ - 어느 Salesforce Developer의 개발 성장기

참고2) https://trailhead.salesforce.com/ - Salesforce Trailhead

Visual Studio Code(이하 VSCode)에는 Terminal이 있기 때문에, Git커맨드를 실행하는 것이 가능합니다.

일단, 현재 프로젝트의 디렉토리를 확인해보겠습니다.

 

참고로, 여기서 Git의 사용법은 이전에 올린 GitHub의 사용법과 같습니다.

2020/06/15 - [Git & GitHub] - [GitHub] GitHub의 사용법을 공부했습니다.

2020/06/17 - [Git & GitHub] - [GitHub] Branch를 이용한 협업 방법을 공부했습니다.

 

그럼, 현재 디렉토리에 있는 프로젝트 파일들을 GitHub에 올려보겠습니다.

 

먼저, 디렉토리를 Git으로 관리하기 위해 "git init" 명령어을 실행합니다.

 

디렉토리의 git 초기화 작업이 성공했다면 다음의 명령어 순으로 입력, GitHub에 프로젝트를 업로드 하겠습니다.

$ git add .
$ git commit -m "first commit"
$ git remote add origin git@*************************.git
$ git push -u origin master

 

 * 업로드 결과 

 

GitHub Repository 확인

github.com/mokochi/Blog_GitHub_From_VSCode.git

 

문제없이 Push가 잘 된 것을 확인할 수 있습니다.

 

또한, README.md파일이 자동으로 생성되어 있는것을 확인할 수 있었는데,

이 파일은 Salesforce 프로젝트 생성시에 자동으로 생성되는 것으로 보입니다.

내용도 그럴싸한 내용이 들어있네요.

(현재 프로젝트와는 전혀 무관하지만..)


이상으로 VSCode의 Terminal을 이용해 Git명령어를 실행, GitHub에 업로드(Push)하는 과정까지 알아보았습니다.

 

 

본 포스트에서는 각 레코드 타입에 따른 레코드의 사용 방법에 대해 알아보겠습니다.


# 레코드의 데이터 타입

 

레코드의 데이터 타입은 Visualforce 페이지나 개체의 페이지 레이아웃을 사용하여 화면을 작성할 때,

데이터를 어떠한 형식으로 입력 및 표시하는가에 따라 구분하여 사용합니다.

 

예를 들어, 똑같은 숫자 데이터를 입력 하더라도, 데이터 타입에 따라 표시되는 형식이 다릅니다.

예) 입력치 : 100

     숫자 : 100

     통화 : \100 (Salesforce에 설정된 언어 및 지역에 따라 단위가 바뀝니다. 일본이면 ¥, 미국이면 $ )

     백분율 : 100%

 

개체에서 레코드를 생성할 때 선택 가능한 데이터 타입은 다음과 같습니다.

데이터 타입 설명
롤업 요약 "누적 집계"라고도 불리며, 주종 관계에서 자식 개체의 특정 항목을 지정하여 데이터의 최대값, 최소값, 합계 등 과 같은 집계 정보를 자동 설정 하는 데이터 타입
수식 직접 지정한 수식을 계산하여 자동 설정 하는 데이터 타입
자동 번호 레코드가 등록 될 때 마다 지정된 형식으로 1씩 증가하는 데이터 타입
예) {0000} 로 설정하면 등록되는 레코드마다 0001, 0002, ... 로 자동 증가
마스터-세부 사항 관계 데이터베이스의 주종 관계와 동일
외부 조회 관계 부모가 외부 개체인 경우에 사용
조회 관계 다른 개체를 참조하기 위한 데이터 타입, 관계 필드를 통해 다른 개체의 레코드를 참조 가능
URL 웹 사이트의 주소 입력이 가능한 데이터 타입, 지정된 URL이 별도의 브라우저 창에 표시
긴 텍스트 영역 긴 문자열을 저장할 때 사용되는 데이터 타입, 최대 131,072자 까지 입력 가능
날짜 날짜를 저장하기 위한 데이터 타입 (yyyy/MM/dd)
날짜/시간 날짜와 시간을 저장하기 위한 데이터 타입 (yyyy/MM/dd HH:mm:ss)
백분율 백분율 숫자를 입력하면 자동으로 백분율 기호가 추가되는 데이터 타입
텍스트 영역(서식 있는 텍스트) 서식이 있는 긴 문자열, 이미지, 링크 등이 입력 가능한 데이터 타입, 최대 131,072자 까지 입력 가능
선택 목록 사용자가 정의한 리스트에서 값을 선택할 수 있는 데이터 타입
선택 목록(다중 선택) 사용자가 정의한 리스트에서 여러개의 값을 선택할 수 있는 데이터 타입
숫자 숫자를 저장하기 위한 데이터 타입
시간 시간을 저장하기 위한 데이터 타입 (HH:mm:ss)
이메일 이메일 주소를 저장하기 위한 데이터 타입
전화 전화번호를 저장하기 위한 데이터 타입
지리적 위치 위치를 저장하기 위한 데이터 타입
텍스트 문자열을 저장하기 위한 데이터 타입, 최대 255자 까지 입력 가능
텍스트(암호화됨) 문자열을 암호화된 형식으로 저장할 수 있는 데이터 타입
텍스트 영역 여러 줄에 걸쳐 문자열을 입력할 수 있는 데이터 타입, 최대 255자 까지 입력 가능
통화 금액을 저장하기 위한 데이터 타입, 통화를 자동으로 형식화 할 수 있음
확인란 Boolean 타입의 정보를 저장하기 위한 데이터 타입, TRUE, FALSE 입력 가능

# 데이터 타입 확인용 개체 및 레코드 등록

 

일단, 데이터 타입의 동작을 확인하기 위한 개체와 레코드를 등록하겠습니다.

알기 쉽도록 각각 "부모""자녀" 라는 명칭의 개체를 만들고,

두 개체는 서로 "마스터-세부 사항 관계" 가 되도록 만들겠습니다.

 

"부모" 개체에는 각각의 데이터 타입을 가진 레코드를 만들것이며, 명칭은 알아서 적당히 지정하셔도 무방합니다.

  ※ "마스터-세부 사항 관계" 타입의 레코드는 자식 개체에서 생성해야 합니다.

"자식" 개체는 단순히 "마스터-세부 사항 관계"를 사용하기 위해 추가한 부속개체이며, 이 개체는 롤업 요약을 사용하기 위한 레코드만 생성하겠습니다.

 

레코드 생성시 추가로 설명이 필요한 항목은 다음과 같습니다.

 

☞ 롤업 요약

 : 롤업 요약 타입의 레코드를 생성하는 경우, "요약된 개체" 에서 자식에 해당하는 개체를 선택하고, 최소값, 최대값 또는 합계를 구할 자식 개체의 항목을 지정해야 합니다.

  또한, 계산 대상이 될 레코드를 선택하기 위한 조건을 추가하고 싶다면,

필터 기준에서 "특정 기준에 맞는 레코드만 계산에 포함되어야 합니다."에 체크를 한 후, 조건을 추가하면 됩니다.

 

☞ 자동 번호

 : 자동 번호는 표시 형식이라는 입력 란에 번호를 생성할 규칙을 지정해야 합니다.

   지정 규칙은 여기 를 참고해주세요.

   여기서는 10자리의 숫자로 생성하도록 다음과 같이 지정하겠습니다.

   자동 번호 표시 형식: {0000000000}

 

☞ 조회 관계

 : 다른 개체를 참조하기 위한 데이터 타입이므로, 참조 대상이 되는 개체를 선택해야 합니다.

  ※ 동일 개체 참조 가능

     예)  부모 -> 부모

 : 하위 관계의 이름을 지정해야 합니다. 이곳에서 지정한 하위 관계 이름을 통해 데이터를 습득하는 것이 가능합니다.

     예) 하위 관계 이름 : Parents1_Parents2_Rel

         SELECT ID, (SELECT Id FROM Parents1_Parents2_Rel) FROM Parents1

 

☞ 수식

 : 수식 타입은 현 개체의 레코드 또는 조회 관계로 참조하고 있는 개체의 레코드 등을 직접적으로 참조하여 데이터를 저장 및 계산할 수 있습니다. 또한, 숫자나 문자열을 고정치로 입력하는 것도 가능합니다.

 ※ 수식 타입은 레코드가 등록(INSERT, UPDATE)이 되고 난 후에 값이 설정되기 떄문에,

    레코드가 등록되기 전에는 값이 없는 상태이니 사용할 때 주의해야 합니다.

 

☞ 선택 목록, 선택 목록(다중 선택)

 : "전역 선택 목록 값 세트 사용"을 사용하기 위해서는 [빌드 - 만들기 - 선택 목록 값 집합]에서 선택 목록의 선택지를 생성해야 합니다.


"부모" 개체 등록 결과입니다.

 

"자녀" 개체 등록 결과입니다.


이제 동작 확인을 위해 각 레코드에 데이터를 넣어보겠습니다.

 

"부모" 개체에는 2개의 레코드, "자식" 개체에는 3개의 레코드를 등록한 후 결과를 확인해보겠습니다.

 

[개발자 콘솔 - Debug - Open Execute Anonymous Window]를 선택해 Apex코드 입력창을 표시합니다.

그 후, 다음의 코드를 입력한 후, [Execute] 버튼을 클릭해 데이터를 등록합니다.

 

먼저, 부모의 조회 관게에 설정할 부모 레코드를 1개 등록합니다.

Parent__c parent = new Parent__c();

parent.Text__c = '부모 참조용';

insert parent;

 

다음으로, 데이터 타입 확인용 부모 레코드를 등록합니다.

 

// 이전에 등록한 부모 레코드 습득
List<Parent__c> pList = [SELECT Id FROM Parent__c];
Parent__c parent = new Parent__c();

// 부모 레코드 생성
parent.Url__c = 'https://www.google.com/';
parent.LongTextArea__c = '긴 텍스트 영역 테스트';
parent.Date__c = Date.Today();
parent.Datetime__c = Datetime.now();
parent.Percent__c = 100;
parent.SelectList__c = 'a';
parent.SelectListMultiple__c = 'a;b;c';
parent.Decimal__c = 500;
parent.Time__c = Datetime.now().time();
parent.Email__c = 'abc@gmail.com';
parent.Phone__c = '010-0000-0000';
parent.TextArea__c = '텍스트 영역 테스트';
parent.Text__c = '텍스트 테스트';
parent.TextEncryption__c = '텍스트 암호화 테스트';
parent.Currency__c = 15000;
parent.Boolean__c = true;
parent.Parents__c = pList.get(0).Id;

// 부모 레코드 INSERT
insert parent;

 

다음으로 자식 레코드를 3개 등록하겠습니다.

// 등록된 부모 레코드를 등록시간 역순으로 습득
List<Parent__c> pList = [SELECT Id FROM Parent__c ORDER BY CreatedDate DESC];

// INSERT용 자식 리스트 정의
List<Child__c> insertChildList = new List<Child__c>();

// 자식 레코드를 3개 생성
Child__c child1 = new Child__c();
child1.Date__c = Date.today();
child1.Parents__c = pList.get(0).Id;
child1.Decimal__c = 100;
child1.Currency__c = 100;

Child__c child2 = new Child__c();
child2.Date__c = Date.today();
child2.Parents__c = pList.get(0).Id;
child2.Decimal__c = 1000;
child2.Currency__c = 1000;

Child__c child3 = new Child__c();
child3.Date__c = Date.today();
child3.Parents__c = pList.get(0).Id;
child3.Decimal__c = 10000;
child3.Currency__c = 10000;

insertChildList.add(child1);
insertChildList.add(child2);
insertChildList.add(child3);

// 자식 레코드 INSERT
insert insertChildList;

# 레코드 값 확인 결과

 

각 레코드의 값이 Visualforce 페이지에서 어떠한 형식으로 표시되는지 확인해보겠습니다.

※ 페이지 에서의 각 항목 표시는 <apex:inputField>만을 사용해서 표시하였습니다.

   기초 연습용 도서 관리 프로그램에서도 같은 것을 사용하였기 때문에, 직접 만들어 보시는 것을 추천합니다.

 

 *결과 화면 

 

소스 코드 아래의 링크에서 확인하실 수 있습니다.

github.com/mokochi/Blog_SFDC_force.com_DataType.git

 


이상으로 레코드의 데이터 타입에 따른 사용 방법에 대해 알아보았습니다.

 

텍스트, 이메일, 전화, URL 등은 단순히 텍스트 형식처럼 사용할 수 있으며, 

숫자, 백분율, 통화 등은 단순히 숫자 형식처럼 사용할 수 있습니다.

 

단지 그 항목의 데이터를 그대로 표시할 경우, 표시 형식이 자동으로 변환될 뿐인 것입니다.

 

그러므로 그때그때 상황에 따라, 필요에 따라 사용하시면 되겠습니다.

 

 

 

 

 

 

 

참고1) https://developer.salesforce.com/docs/atlas.en-us.224.0.apexcode.meta/apexcode/apex_dev_guide.htm - Apex 개발자 가이드

참고2) https://developer.salesforce.com/docs/atlas.en-us.226.0.pages.meta/pages/pages_intro.htm - Visualforce 개발자 가이드

 

 

 

 

 

 

 

 

 

 

'Salesforce.com' 카테고리의 다른 글

[SFDC] Salesforce란?  (0) 2020.06.22

+ Recent posts