Force.com중 Apex Code를 정리 합니다.


Apex Code 문법



변수 타입

{|cellspacing="0" cellpadding="2" border="1" width="100%" bgcolor="#FFFFFF" align="center" |- |width="20%" align="center" valign="middle" style="background-color:#eee;"|String |width="80%"|

  • 문자열
  • 선언
    • String item = new String();
    • String item = '~';
  • 제공 함수
    • Integer length()
    • Boolean equals(String), Boolean equalsIgnoreCase(String), Integer compareTo(String)
    • Boolean startsWith(String), Boolean contains(String), Boolean endsWith(String)
    • Integer indexOf(String), Integer indexOf(String, Integer), Integer lastIndexOf(String)
    • String trim()
    • String replace(String, String), String replaceAll(String, String), String replaceFirst(String, String)
    • String substring(Integer), String substring(Integer, Integer)
    • List split(String), List split(String, Integer)
    • String toLowerCase(), String toLowerCase(String)
    • String toUpperCase(), String toUpperCase(String)
    • void addError(APEX_OBJECT 또는 String)

  • 변환
    • Integer
      • Integer tmpInteger = Integer.valueOf(tmpStr);
      • String tmpStr = String.valufOf(tmpInteger);
    • Boolean
      • Boolean tmpBoolean = (tmpStr == 'true') ? true:false;
      • String tmpStr = (tmpBoolean) ? 'true':'false';
    • Date
      • Date tmpDate = Date.valufOf(tmpStr + ' 00:00:00');
        • tmpStr : yyyy-MM-dd
      • String tmpStr = tmpDate.year() + '-' + tmpDate.month() + '-' + tmpDate.day();
    • Datetime
      • Datetime tmpDatetime = Date.valufOf(tmpStr);
        • tmpStr : yyyy-MM-dd HH:mm:ss
      • String tmpStr = tmpDatetime.year() + '-' + tmpDatetime.month() + '-' + tmpDatetime.day() + ' ' + tmpDatetime.hour() + ':' + tmpDatetime.minute() + ':' + tmpDatetime.second();
    • Blob
      • Blob tmpBlob = Blob.valueOf(tmpStr);
      • String tmpStr = tmpBlob.toString();
        |- |align="center" valign="middle" style="background-color:#eee;"|배열 |
  • 선언
    • String[] data = new String3;
    • String[] data = new String3 {val1, val2, val3};
    • String data = new List();
    • String data = new List(다른_List);
  • 제공 함수
    • Integer size()
  • 사용법
    • data[0], data[1], data2, ...
  • 변환
    • String = List;
      |- |align="center" valign="middle" style="background-color:#eee;"|Integer, Long |
  • Integer : 32-bits 정수, Long : 64-bits 정수
  • Integer = Integer.valueOf(String)
  • Long long = ~L;
    |- |align="center" valign="middle" style="background-color:#eee;"|Decimal, Double |
  • Decimal : 32-bits 실수, Double : 64-bits 실수
    |- |align="center" valign="middle" style="background-color:#eee;"|Boolean |
  • Boolean : true, false, null
    |- |align="center" valign="middle" style="background-color:#eee;"|Date, Datetime |
  • Date : 날자, Datetime : 날자 + 시간
  • Date baseDate = Date.parse('2011. 12. 5');
  • Date var20111101 = baseDate.addMonths(-1).toStartOfMonth();
  • Date var20111130 = baseDate.toStartOfMonth().addDays(-1);
    |- |align="center" valign="middle" style="background-color:#eee;"|ID |
  • ID : 18 문자의 레코드 아이디
    |- |align="center" valign="middle" style="background-color:#eee;"|Object | |- |align="center" valign="middle" style="background-color:#eee;"|sObject |
  • 개체
  • 선언
    • Account item = new Account();
    • Account item = new Account(name1 = 'value1', name2 = 'value2');
    • Account[] data = Query_문;
    • Account data = Database.query('Query_문');
  • 사용
    • item.~ : Field 값
    • item.getSObjectType() == Account.sObjectType : 'Account'라는 object type을 반환
      |- |align="center" valign="middle" style="background-color:#eee;"|Blob | |- |align="center" valign="middle" style="background-color:#eee;"|this | |- |align="center" valign="middle" style="background-color:#eee;"|List |
  • 선언
    • List data = new List();
    • List data = new List {val1, val2, val3};
    • List data = new type0;
    • List data = new type {val1, val2, val3};
    • List data = new List(다른_List);
  • 제공 함수
    • get(0), set(0, ~), clear();
    • add(~), remove(0), size(), isEmpty()
      |- |align="center" valign="middle" style="background-color:#eee;"|Set |
  • 선언
    • Set data = new Set();
    • Set data = new Set {val1, val2, val3};
    • Set data = new Set(다른_Set);
  • 제공 함수
    • clear(), isEmpty(), size()
    • add(data), contains(data), remove(data)
      |- |align="center" valign="middle" style="background-color:#eee;"|Map |
  • 선언
    • Map<keyType, valueType> name = new Set<keyType, valueType>();
    • Map<keyType, valueType> name = new Set<keyType, valueType> {key1 => val1, key2 => val2};
    • Map<ID, Contact> m = new Map<ID, Contact>(id, lastname from contact);
  • 제공 함수
    • containsKey(key), keySet(), values(), clear(), isEmpty()
    • get(key), put(key, value), remove(key)
      |- |align="center" valign="middle" style="background-color:#eee;"|Enums |
  • 선언
    • public enum Season {WINTER, SPRING, SUMMER, FALL}
  • 사용법
    • Season e = Season.WINTER;
  • 제공 함수
    • name(), ordinal(), values()
  • System-defined enums
    • System.StatusCode, System.XmlTag, System.LoggingLevel, System.RoundingMode
    • System.SoapType, System.DisplayType, ApexPages.Severity, Dom.XmlNodeType
      |}
  • Primitive Data Types
    Boolean     : true, false
    Date
    Datetime
    Double
    ID          : 18 Character Apex record identifier
    Integer
    String
    배열        : [](.md) 로 표시

  • SObject Type, SObject Fields
  • Lists
    List zzStr = new List();
    zzStr.set(0, "tmpStr");
    zzStr.get(0);
    zzStr.clear();

  • Sets
    Set zzStr = new Set();
    zzStr.add("tmpStr");
    zzStr.remove(1);

  • Maps
    Map zzStr = new Map();
    zzStr.put("zzName", "zzValue");
    zzStr.get("zzName");

  • Not Support DML Statements
    User, Profile, Territory, RecordType, Transaction, WebLink, BusinessHours, BusinessProcess, CategoryNode, Process
  • UserInfo
  • Currency
  • Integer, Double, Boolean, String, Datetime, Date, Math
  • List, Set, Map, SObject, Exception


Data 지정 방법

  • POJO (Plan Old Java Object)
    • obj.name
    • obj'name'
    • obj.getName(), obj.setName(value)
    • obj.get('name'), obj.set('name', value)
    • obj.name0


제어문

 if (~) {
 } else {
 }


Loops

  • continue, break

    do {
     statement;
     break;
     continue;
    } while (Boolean_condition);
    
    while (Boolean_condition) {
     statement;
    }
    
    for (initialization; Boolean_exit_condition; increment) {
     statement;
    }
    
    for (variable : array_or_set) {
     statement;
    }
    
    for (variable : [inline_soql_query](inline_soql_query.md)) {
     statement;
    }


Exception

    try {
        throw ~;
    } catch (Exception ex) {
        //---   System.ArrayException, DmlException, MathException, NullPointerException
        //---   QueryException, StringException, TypeException
    } finally {
    }




Control - Class



Class 정의

  • "설정 -> App 설정 -> 개발 -> Apex 클래스" 메뉴
    public | private | global
       [| abstract | with sharing | without sharing](virtual)  class | interface  ClassName
       [implements InterfaceNameList]  [ClassName](extends) {
       [public | private | protected | global]   [static]   [final](final.md)   String   var = value;
       [public | private | protected | global]   [override]   [static](static.md)   String   func()  { }
    }
  • with sharing
    • <- user’s permissions, field-level security, sharing rules
    • 소유자 (사용자)
    • 역할
    • 공유 설정
    • 프로필
    • Field Level Security
    • Transient String name; //--- view state에 저장되지 않음
      그림:Class001.png

Class 상속

  • virtual -> extend or override, abstract -> override

  • this, super

    public virtual class Parent {
       public virtual String getStrParent() {
           return ‘Parent String’; 
       } 
    }
    
    public class Child extends Parent {
       public Child() {
           super();
       }
    
       public override String getStrParent() {
           return super.getStrParent() + ‘ : Child String’;
       } 
    }

    ``` public virtual class Parent { public String strParent = null;

    public Parent() { }

    public void Func01() { }

    public String getStrParent() {

       return strParent;

    } }

    public class Child extends Parent { public Child() {

        super();     //--- Parent의 생성자를 호출 합니다.
        //--- TODO : 여기에 코딩

    }

    //--- Parent의 Method를 재설정 합니다. public override void Func01() {

       getStrParent();

    } } ```


  • Interface 상속

    public virtual interface Parent {
    }
    
    public interface Child extends Parent {
    }

  • 상속 확인

    • A instanceof B


Apex Properties

  • Apex Properties 정의
    [public | private | protected | global]   [virtual, abstract, overrid](static,) 
    String var { [public | private | protected] get; [~](~.md) set;}

  • Apex Properties
    • set 함수에서 value는 System이 생성하여 전달하는 인수값 입니다.
      public class BasicClass {
       public  String  varName {
           get {
               return varName;
           }
           set {
               name = value;
           }
       }
      }


Parameterized Interface

 public virtual interface Pair {
     public T getFirest();
     public void setFirst(T val);
 }

 public StringPair implements Pair {
 }


Annotations

  • @deprecated :
  • @future : 비동기적으로 실행되는 Method, 200 호출 / user, 24시간
  • @isTest : 테스트 클래스 표시
  • @ReadOnly : in Web services, Schedulable interface
  • @RemoteAction : JavaScript에서 함수 호출


내장 변수

  • {!$ObjectType.Account} === Schema.SObjectType.Account.getKeyPrefix()
  • {!$ObjectType.Account.fields.Name.label}
  • Object, sObject
  • NS__Object__c, NS__Field__c / NS.Class.Method()
  • Iterable, Iterators -> Database.batchable


Control - Testing Apex


Apex Code로 프로그램을 작성하면 이를 배포하기 위해서는 전체 코딩된 라인중 75% 이상이 테스트 되어야 합니다. (Code Coverage Result가 75% 이상) Force.com에서 제안하는 테스트 방식을 살펴보면 해당 코드가 한번 이상 수행이 되면 테스트가 된 것으로 처리를 하고 있습니다. 따라서 Code Coverage Result를 높이기만을 원한다면 다양한 테스트 코드를 작성할 필요는 없고 각각의 라인이 한번 이상 실행이 되도록 테스트 코드를 작성하면 됩니다.

  • Code Coverage Result를 높이는 방법
  1. 분기문, 제어문 등에서 각각의 코드 블럭이 실행될 수 있도록 데이터를 구성 합니다. (추천)
  2. 테스트가 완료된 코드 블럭에 의미없는 코드를 추가하여 라인수를 늘입니다. (비추천)


Test Class 사례

  • ClassName 클래스를 테스트하기 위한 Test 클래스 샘플

    • ClassName의 모든 라인이 수행될 수 있도록 Test 클래스를 작성하여야 함

    • 배포 등을 위해서는 전체 라인중 75%가 테스트(Code Coverage Result)가 되어야 함

      @IsTest
      private class ClassNameTest {
      private static testMethod void testMain() {
          ClassName test = null;
        
      //--- Test를 위한 사용자 설정 User user = [id from User where alias='auser'](select); System.RunAs(u1) { //--- Test를 위한 데이터 설정 manage = new Manage();
      //--- Test 코드 작성 test = new ClassName(); test.setManage(manage);
      System.assert(actual==expected, 'Character.isAscii(\'' + charactr + '\') returned ' + actual); System.assertEquals(singletotalMiles, totalMiles); Test.startTest(); //--- Limits를 초기화하고 테스트 시작 ~ Test.stopTest(); } } }

  • Apex Batch 테스트 프로그램

    @IsTest
    private class BatEvaluationTest {
      private static testmethod void testMain() {
          BatEvaluation test = null;
          List scope = null;
        
    Test.StartTest(); //--- Apex Batch에 전달할 scope 데이터 생성 scope = new List(); scope.add(new Evaluation__c());
    //--- Apex Batch의 각 Method를 별도로 실행 test = new BatEvaluation(); test.start(null); test.execute(null, scope); test.finish(null); Test.stopTest(); } }


System.assert

  • System.assert(boolean) : boolean 값이 true이면 OK
  • System.assert(boolean, e.getMessage()) : boolean 값이 true이면 OK, boolean 값이 false이면 두번째 인자를 메시지로 표시
  • System.assertEquals(dataA, dataB msg) : dataA와 dataB의 값이 동일하면 OK
  • System.assertNotEquals(dataA, dataB msg) : dataA와 dataB의 값이 다르면 OK
  • System.assert(BooleanExceptionMessage);
    System.assert(false); System.assert('a' == 'A');
  • System.assertEquals(expectedValue, actualValueExceptionMessage);
    System.assertEquals('Hello to you!', sayHelloWorld('to you!'));
  • System.assertNotEquals(expectedValue, actualValueExceptionMessage);


Test 실행 방법

  • "설정 -> App 설정 -> 개발 -> Apex 클래스 -> 모든 테스트 실행"에서 테스트
  • "설정 -> App 설정 -> 개발 -> Apex 테스트 실행"에서 테스트
  • Eclipse에서 Class에서 오른쪽 마우스를 눌러 "Force.com -> Run Tests" 메뉴를 실행 합니다.


Control - Trigger



Trigger 개요

  • Trigger 종류

    • insert : before/after insert
    • update : before/after update
    • delete : before/after delete
    • upsert : before/after insert/update
    • merge : before/after delete, before update
    • undelete : after undelete (Account, Asset, Campaign, Case, Contract, Custom objects, Event, Lead, Opportunity, Product, Solution, Task)
  • Trigger 적용 예외

    • Cascading delete, Mass ~, …
    • Opportunity : amoutn, ForecastCategory, isWon, …
  • 트리거 메뉴

    • "설정 -> App 설정 -> 사용자 정의 -> '개체' -> 트리거" 메뉴
    • "설정 -> App 설정 -> 작성 -> 개체 -> 트리거 '새로 만들기'"
  • Trigger 변수

    • Trigger.old, Trigger.new, Trigger.oldMap, Trigger.newMap, Trigger.size
    • Trigger
      • isBefore, isAfter, isInsert, isUpdate, isDelete, isUndelete
        public Integer size = Trigger.size;
        public PaymentType__c[](.md) oldData = Trigger.old;    
        public PaymentType__c[](.md) newData = Trigger.new;    
        Trigger.old[idx], Trigger.new[idx](idx.md)

  • Trigger 사례

    trigger StandardTrigger on Account (before insert, before update, before delete,
                                                   after insert,   after update,    after delete) {
      //--- @future, 비동기 WebService
      //--- sObject.addError('~');
      //--- Trigger.size, oldMap, newMap, old (ReadOnly), new
    if (Trigger.isInsert && Trigger.isBefore) {
          for (Account item : Trigger.old) {
          }
          for (Account item : Trigger.new) {
              //--- 수정 가능
          }
      }
    
      if (Trigger.isInsert && Trigger.isAfter) {
          for (Account item : Trigger.old) {
          }
          for (Account item : Trigger.new) {
          }
      }
    }


Triggers and Bulk Triggers

    -   Bulk Triggers
        Data import, Bulk Apex API calls, Mass actions
        Recursive Apex Code methods and triggers that invoke bulk DML statements

    trigger  on  bulk () {
        //---   trigger_event   : before insert, before update, before delete, after ~

        //---   isInsert, isUpdate, isDelete, isUndelete, isBefore, isAfter

        //---   Trigger.new, Trigger.newMap, Trigger.old, Trigger.oldMap, Trigger.size

        //---   Trigger.oldMap.get(q.opportunity__c).addError('Cannot delete opportunity with a quote');
        //---   Trigger.new[i](i.md).Primary__c.addError('Primary quote cannot be marked non-primary');

        try {
            Dictionary__c obj = new Dictionary__c(Name='Dictionary deploy test');
            insert obj;
        } catch(DmlException e) {
            System.assert(e.getMessage().contains('first error: FIELD_CUSTOM_VALIDATION_EXCEPTION,'), e.getMessage());
        }
    }   //---   최대 32,000 characters

    trigger helloWorldAccountTrigger on Account (before insert) 
    {
        //---   before insert, before update, after insert, after update, after delete
        //---   Trigger.isBefore

        Account[](.md) accs = Trigger.new;
        MyHelloWorld.addHelloWorld(accs);
      
Contact c = new Contact(lastName = 'Weissman'); c.accountId = a.Id; insert c; List aa = [id, name from account where name = 'Acme'](select); c = [account.name from contact where id = :c.id](select); c.account.name = 'salesforce.com'; c.lastName = 'Roth'; update c; update c.account; upsert delete delete
System.assertEquals('xxx', a.accountNumber); }
Savepoint sp = Database.setSavepoint(); Database.rollback(sp); throw ; try { } catch () { }


Trigger Sample 1

 /**
  *      프로그램 명     : DictionaryTrigger.trigger Trigger
  *      프로그램 설명   : Dictionary 개체용 Trigger 샘플
  *      작성자          : 산사랑
  *      작성일          : 2008.06.19 ~ 2008.06.19
  *
  *      Copyright (c) 2000-2008 pnuskgh, All rights reserved.
  */
 trigger DictionaryTrigger on Dictionary__c (before insert, before update, before delete)
 {
     Double tmpNum = 0.0;

     if (Trigger.isBefore) {
         if (Trigger.isInsert) {
             for (Dictionary__c obj:Trigger.new) {
                 obj.num__c = 1;
             }
         }

         if (Trigger.isUpdate) {
             for (Dictionary__c obj:Trigger.new) {
                 if (obj.num__c == 11) {
                     obj.num__c = obj.num__c + 100;
                 } else {
                     obj.num__c = obj.num__c + 10;
                 }
                 if (150 < obj.num__c) {
                     obj.addError('Error : You can\'t update this record.');
                     obj.num__c.addError('Error : You can\'t update this record.');
                 }
             }
         }

         if (Trigger.isDelete) {
             for (Dictionary__c obj:Trigger.old) {
                 tmpNum = obj.num__c;
             }
         }
     }
 }


Trigger Test Class Sample 1

 /**
  *      프로그램 명     : DictionaryDeployClass Class
  *      프로그램 설명   : DictionaryTrigger Trigger를 테스트하는 클래스
  *      작성자          : 산사랑
  *      작성일          : 2008.06.19 ~ 2008.06.19
  *
  *      Copyright (c) 2000-2008 pnuskgh, All rights reserved.
  */
 public class DictionaryDeployClass {
     public static testmethod void DictionaryDeployTest()
     {
         Double tmpNum = 0.0;

         System.debug('Start insert trigger test.');
         Dictionary__c obj = new Dictionary__c(Name='Dictionary deploy test');
         insert obj;

         obj = [select Id, Name, num__c
                  from Dictionary__c
                 where Id = :obj.Id]; 
         System.assertEquals(1, obj.num__c);


         System.debug('Start update trigger test.');
         tmpNum = obj.num__c + 10;
         update obj;

         obj = [select Id, Name, num__c
                  from Dictionary__c
                 where Id = :obj.Id];
         System.assertEquals(tmpNum, obj.num__c);


         try {
             System.debug('Start delete trigger test.'); 
             delete obj;

obj = [select Id, Name, num__c from Dictionary__c where Id = :obj.Id]; } catch(QueryException e) { System.debug(e.getMessage()); System.assert(e.getMessage().contains('List has no rows for assignment to SObject'), e.getMessage()); } } }


Trigger Sample 2

 /**
  *      프로그램 명     : OpportunityTrigger.trigger Trigger
  *      프로그램 설명   : Forecast 데이터만 영업기회에서 분리하여 관리
  *      작성자          : 산사랑
  *      작성일          : 2008.06.20 ~ 2008.06.20
  *
  *      Copyright (c) 2000-2008 pnuskgh, All rights reserved.
  */
 trigger OpportunityTrigger on Opportunity (before insert, after insert, before update, before delete)
 {
     if (Trigger.isAfter) {
         if (Trigger.isInsert) {
             for (Opportunity opp:Trigger.new) {
                 Forecast__c obj = new Forecast__c(OwnerId = opp.OwnerId, Name = opp.Name, 
                     Amount__c = opp.Amount__c, GP__c = opp.GP__c, 
                     Probability__c = opp.Probability, opportunity__c = opp.Id);
                 insert obj;
             }
         }
     }
   
if (Trigger.isBefore) { if (Trigger.isUpdate) { for (Opportunity opp:Trigger.new) { Forecast__c obj = [select Id, OwnerId, Name, Amount__c, GP__c, Probability__c, opportunity__c from Forecast__c where opportunity__c = :opp.Id]; obj.OwnerId = opp.OwnerId; obj.Name = opp.Name; obj.Amount__c = opp.Amount__c; obj.GP__c = opp.GP__c; obj.Probability__c = opp.Probability; update obj; } } if (Trigger.isDelete) { for (Opportunity opp:Trigger.old) { Forecast__c obj = [select Id, OwnerId, Name, Amount__c, GP__c, Probability__c, opportunity__c from Forecast__c where opportunity__c = :opp.Id]; delete obj; } } } }


Trigger Test Class Sample 2

 /**
  *      프로그램 명     : OpportunityDeployClass Class
  *      프로그램 설명   : OpportunityTrigger Trigger를 테스트하는 클래스
  *      작성자          : 산사랑
  *      작성일          : 2008.06.20 ~ 2008.06.20
  *
  *      Copyright (c) 2000-2008 pnuskgh, All rights reserved.
  */
 public class OpportunityDeployClass {
     public static testmethod void OpportunityDeployTest()
     {
         Boolean flagError = false;
         Forecast__c obj = Null;

         System.debug('Start insert trigger test.');
         Opportunity opp = new Opportunity(Name = 'Deploy test', Amount__c = 100, GP__c = 20,
             StageName = '수주확신(90%)', CloseDate = System.today());
         insert opp;

         opp = [select Id, OwnerId, Name, Amount__c, GP__c, Probability
                  from Opportunity
                 where Id = :opp.Id];

         obj = [select Id, OwnerId, Name, Amount__c, GP__c, Probability__c, opportunity__c
                  from Forecast__c
                 where opportunity__c = :opp.Id];

         System.assertEquals(opp.OwnerId, obj.OwnerId);
         System.assertEquals(opp.Name, obj.Name);
         System.assertEquals(opp.Amount__c, obj.Amount__c);
         System.assertEquals(opp.GP__c, obj.GP__c);
         System.assertEquals(opp.Probability, obj.Probability__c);
         System.assertEquals(opp.Id, obj.opportunity__c);

         System.debug('Start update trigger test.');
         opp.GP__c = 30;
         update opp;

         obj = [select Id, OwnerId, Name, Amount__c, GP__c, Probability__c, opportunity__c
                  from Forecast__c
                 where opportunity__c = :opp.Id];

         System.assertEquals(opp.OwnerId, obj.OwnerId);
         System.assertEquals(opp.Name, obj.Name);
         System.assertEquals(opp.Amount__c, obj.Amount__c);
         System.assertEquals(opp.GP__c, obj.GP__c);
         System.assertEquals(30, obj.GP__c);
         System.assertEquals(opp.Probability, obj.Probability__c);
         System.assertEquals(opp.Id, obj.opportunity__c);
       
try { System.debug('Start delete trigger test.'); delete opp; obj = [select Id, OwnerId, Name, Amount__c, GP__c, Probability__c, opportunity__c from Forecast__c where opportunity__c = :opp.Id]; } catch(QueryException e) { if (e.getMessage().contains('List has no rows for assignment to SObject')) { flagError = true; } else { throw e; } } System.assert(flagError); } }


Control - Scheduler


  • "설정 -> App 설정 -> 개발 -> Apex 클래스 -> Apex 예약" 메뉴 그림:Schedular001.png



  • "설정 -> 관리 설정 -> 모니터링 -> 예약된 작업" 메뉴에서 모니터링

  • Scheduler 생성

    global class StandardScheduler implements Schedulable {
       global void execute (SchedulableContext sc) {
           Batchable batch = null; 
    
           //--- sc.getTriggerId()  CronTrigger 개체
           batch = new Batchable();
           Database.executebatch(batch);
       }
    }

  • Scheduler 사용법

    • 초(0-59) 분(0-59) 시(0-23) 일(1-31) � 월(1-12) 주(1-7, 1.일요일) 년(1970-2099)
      String sch = ‘20 30 8 10 2 ? * ‘;
      String id = system.schedule(‘name’, sch, StadnardScheduler);


Control - Batch Apex



Database.Batchable Interface

Apex Code에서 Batch 프로그램을 작성하려면 Database.Batchable Interface를 구현 하여야 합니다.

  • global (Database.QueryLocator | Iterable) start(Database.BatchableContext bc) {}
    • execute Method에서 처리할 레코드를 수집하여 반환 합니다.
  • global void execute(Database.BatchableContext BC, list<P>) {}
    • 실제로 Batch 처리가 이루어지는 method 입니다.
    • Default로 200개의 records씩 전달되어 실행이 되며 각 execute은 별개의 Transaction으로 처리가 됩니다.
  • global void finish(Database.BatchableContext BC) {}
    • Batch 처리가 모두 완료된 후에 호출되는 method 입니다.


Database.AllowsCallouts Interface

Apex Batch에서 HTTP request를 호출하는 프로그램을 작성하려면 Database.AllowsCallouts Interface를 implement 하여야 합니다.


Database.Stateful Interface

Apex Batch 처리를 위한 Class에서 선언한 변수의 값을 계속 유지하려면 Database.Stateful Interface를 implement 하여야 합니다.


Database.BatchableContext

  • getJobId() : 해당 Apex Batch Job의 ID를 반환 합니다.


Database

  • executeBatch Method : Apex Batch를 실행 합니다.
    ID batchId = null;
    BatSession batch = null;
        
    batch = new BatSession(); batchId = Database.executeBatch(batch); //batchId = Database.executeBatch(batch, 200); //--- 200. 한번에 처리하는 레코드 갯수


Batch Apex 사례

  • Batch Apex 선언

    • Database.AllowsCallouts Interface : HTTP 호출시 implement
    • Database.Stateful : Class에서 선언한 변수 값을 유지하려면 implement
      global class BatAccount implements Database.Batchable, Database.Stateful {
       global Database.QueryLocator start(Database.BatchableContext ctx) {
          return Database.getQueryLocator([Id, Name FROM Account](SELECT));
       }
      
      global void execute(Database.BatchableContext ctx, List scope) { for (Account item : scope) { } }
      global void finish(Database.BatchableContext ctx) { ID id = ctx.getJobID(); //--- AsyncApexJob 개체 } }

  • Batch Apex 사례

    global class BatSession implements Database.Batchable, Database.Stateful {
      global Database.QueryLocator start(Database.BatchableContext ctx) {
          Datetime tmpDate = null;
        
    tmpDate = Datetime.now(); tmpDate.addDays(-3); return Database.getQueryLocator([SELECT Id FROM Session__c WHERE CreatedDate < :tmpDate]); }
    global void execute(Database.BatchableContext ctx, List scope) { delete scope; }
    global void finish(Database.BatchableContext ctx) { AsyncApexJob job = null; AsyncApexJob job = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email FROM AsyncApexJob WHERE Id = :ctx.getJobId()]; } }


Batch Job 모니터링

  • AsyncApexJob : Batch 진행 사항을 저장
  • "설정 -> 관리 설정 -> 모니터링 -> Apex 작업" 메뉴에서 모니터링
  • [Apex 작업](Salesforce_-_관리 설정.md#Apex 작업.md)


Batch 제약 사항

  • start method에서 QueryLocator를 사용할 경우 최대 5000만 레코드만 처리가 가능 합니다.
    • start method에서 Iterable을 사용할 경우 최대 레코드 제약은 그대로 적용이 됩니다.
  • Apex governor limits are reset for each execution of execute
  • 동시에 최대 5개의 Batch Job만 처리가 가능 합니다.
  • A user can have up to 5 query cursors open at a time
    • Apex query cursors, Batch cursors, Visualforce cursors는 각각 최대 5개까지 동시에 사용이 가능 합니다.
  • Aggregate Query는 Batch Apex에서 start 함수의 결과로써 사용할 수 없습니다.


Control - Web Service


  • Web Services 생성 in Apex Code

    global class StandardWebServices {
       webService static String getTitle(String title, Account argAccount) {
           return '[+ title + '](')';
       }
    }

  • Web Services 호출 in Visualforce Page

    
    
    
    
    var account = sforce.sObject("Account");    //--- id, type, name
    var title = sforce.apex.execute(“StandardWebServices”, “getTitle”, 
                 {title:”~”, argAccount:account});
    • sforce.debug.trace = true;


Control - HTTP


 Http http       = null; 
 HttpRequest req = null; 
 HttpResponse res = null;
 String strHeader = null;
 String contentType = null, response = null;

 try {
     req = new HttpRequest();
     req.setEndpoint('http://www.apexdevnet.com/'); 
     req.setMethod('GET');
     req.setHeader(‘Content-Type’, ‘application/soap+xml’);
     req.setTimeout(60000);
     req.setBody(‘name1=value1&name2=value2’);
     req.setCompressed(false);

     //--- Basic Authencation
     strHeader = EncodingUtil.base64Endoce(Blob.valueOf(userid + ‘:’ + pwd))
     req.setHeader(‘Authorization’, ‘BASIC ‘ + strHeader);

     http = new Http();
     res = http.send(req); 
     if (res.getStatusCode() == 404) {
     } else {
         contentType = resp.getHeader('Content-Type');
         response = resp.getHeader('Content-Length');
         this.theXMLDom = new xmldom(res.getBody());

         dom.document doc = res.getBodyDocument();  
         dom.XmlNode [](.md) node = doc.getRootElement().getChildElements();  

         //--- Atachement로 저장
         Attachment attach = new Attachment();
         attach.Name = “~’;
         attach.ContentType = “~”;
         attach.body = Blob.valueOf(res.getBody());
         attach.ParenetId = ~;
         insert attach;
     }
 } catch (System.CalloutException e) {
     this.theXMLDom = null;
 }


Control - RemoteAction


RemoteAction은 Visualforce Page에서 JavaScript를 사용하여 Controller의 Method를 호출하는 방법 입니다.

  • Apex Code

    global class MyJSController {
       public String accountName { get; set; } 
       public static Account account { get; set; } 
    
       @RemoteAction
       global static Account getAccount(String accountName) { 
           account = [
               SELECT id, name, phone 
                FROM Account 
               WHERE name =  :accountName ];
           return account;
       } 
    }

  • Visualforce Page

     
       var accountNameJS = null; 
    
       accountNameJS = "오픈소스 비즈니스 컨설팅"; 
       MyJSController.getAccount(
           accountNameJS,            //--- 전달되는 인자 
           function(result, event) {   //--- result : 반환 값 
               if (event.status) { 
                   //--- 정상 처리 
                   //--- 반환된 값은 result.name
                   //--- 반환된 배열 result[2](2.md).name
               } else if (event.type === 'exception') {
                   //--- Exception 오류 처리 
               } else { 
                   //--- 오류 처리 
               }
           }, 
          {escape:true} 
    ); 
     
    

  • 참고 문헌


Control - Email Service


  • Single Mail 발송

    Messaging.SingleEmailMessage email = null;
    Messaging.EmailFileAttachment file = null;
    Messaging.SendEmailResult[](.md) result = null;
    
    email = new Messaging.SingleEmailMessage();
    email.setSubject(String);
    email.setToAddress(String[](.md));
    email.setPlainTextBody(String);
    
    file = new Messaging.EmailFileAttatchment();
    file.setFileName(‘~’);
    file.setBody(Blob);
    
    email.setFileAttachments(new Messaging.EmailFileAttachment[](.md) {file});
    result = Messaging.sendEmail(new Messaging.SingleEmailMessag[](.md) {email});


Custom Setting


  • Setting__c.getValues(Name).Value__c
    • Setting__c : Custom Setting 개체명
    • Name : 레코드의 Name
    • Value__c : 레코드의 Value__c라는 필드의 필드값


Sandbox


  • Sandbox 명이 de일 경우, Sandbox의 로그인 아이디는 userid.de 입니다.


Deploy


  • Eclipse에서 deploy
    • 클래스를 선택한 후 오른쪽 마우스를 누릅니다.
    • "Force.com -> Deploy to Server..." 메뉴를 선택하여 deploy 합니다.
  • Setup에서 deploy
    • 운영의 "설정 -> App 설정 -> 배치 -> 연결 배포"에서 "인바운드 변경 허용"을 선택 합니다.
    • Sandbox의 "설정 -> App 설정 -> 배치 -> 아웃바운드 변경 세트"에서 변경세트를 작성하고 업로드 합니다.
    • 운영의 "설정 -> App 설정 -> 배치 -> 인바운드 변경 세트"에서 업로드된 변경 세트를 배포 합니다.
  • Deploy의 제약 사항
    • Class와 Trigger를 75% 이상 테스트 되어야 합니다.
    • 하나의 class가 deploy 되더라도 모든 class에서 검증이 들어 갑니다. (Source Coverage의 평균이 75% 이상이 되어야 합니다.)
    • Test Class는 실제 운영 서비스에 있는 테스트 클래스가 실행 되므로 먼저 테스트 클래스부터 deploy 해야 합니다.


Force.com 내장 개체



System

  • Debug
    • System.debug(Message);
    • System.debug(logLevel, Message); :ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST
  • Date and Time
    • System.today() : 오늘 날자를 반환한다.
    • System.now() : 오늘 날자와 시간을 반환한다.


암호화

  • 암호화 key 생성
    • Blob key = Crypto.generateAesKey(256)
  • 암호화
    • String 암호문 = EncodingUtil.base64Encode(Crypto.encryptWithManagedIV('AES256', key, Blob.valueOf('평문')));
  • 복호화
    • String 평문 = Crypto.decryptWithManagedIV('AES256', key, EncodingUtil.base64Decode('암호문')).toString();
  • 해시키 생성
    • 'MD5' + 해시키 = Crypto.generateDigest('MD5', '해시키로 변환할 문자열');
  • String과 Blob간 변환
    • Blob에 문자열이 저장되어 있을 경우
      • String strBlob = dataBlob.toString();
      • Blob dataBlob = Blob.valufOf(strBlob);
    • Blob에 바이너리가 저장되어 있을 경우
      • String strBlob = EncodingUtil.base64Encode(dataBlob);
      • Blob dataBlob = EncodingUtil.base64Decode(strBlob);


인코딩

  • 인코딩 : EncodingUtil.base64Encode(~)
  • 디코딩 : EncodingUtil.base64Decode(~)
  • URL 인코딩 : EncodingUtil.urlEncode(~, “UTF-8”)
  • URL 디코딩 : EncodingUtil.urlDecode(~, “UTF-8”)


Logging

  • System Logging Levels (System.LoggingLevel enum)
    • ERROR
    • WARN
    • INFO
    • DEBUG
    • FINE
    • FINER
    • FINEST
  • 로그 남기기 System.debug('MsgTxt'); //--- Default Loggin Level인 Logginglevel.DEBUG 가 적용됨) System.debug(Logginglevel.INFO, 'MsgTxt');
  • Apex Code별 로그 레벨 설정
    • Apex 클래스 : "설정 -> App 설정 -> 개발 -> Apex 클래스" 메뉴에서 원하는 클래스를 선택한 후 "로그 필터" 탭에서 설정
      그림:ApexLog01.png
    • Apex 트리거 : "설정 -> App 설정 -> 개발 -> Apex 트리거" 메뉴에서 원하는 트리거를 선택한 후 "로그 필터" 탭에서 설정 그림:ApexLog02.png
  • 로그 확인
    • "시스템 로그" 메뉴에서 확인
    • "설정 -> 관리 설정 -> 모니터링 -> 디버그 로그"에서 확인


Dynamic Apex



sObject 정보 획득

{|cellspacing="0" cellpadding="2" border="1" width="100%" bgcolor="#FFFFFF" align="center" |- |width="25%" align="center" valign="middle" style="background-color:#eee;"|sObject |width="75%" valign="top"|

  • sObject obj = new Custom__c();
  • Map<String, Schema.SObjectType> objAll = Schema.getGlobalDescribe();
    • 표준 개체는 key에 namespace가 붙지 않습니다.
    • 사용자 정의 개체는 namespace가 다를 경우, key에 "NS__" 와 같은 형태의 namespace가 앞에 붙습니다.

  • Object value = obj.get('name');
  • obj.put('name', 'value');
  • obj.put(field, 'value');
  • sObject objParent = obj.getSObject('ParentCustom__c');
    • SELECT Id, ParentCustom__c FROM Custom__c LIMIT 1
  • sObject objChild = obj.getSObjects('ChildCustom__c');
    • SELECT Id, (SELECT Name FROM ChildCustom__c LIMIT 1) FROM Custom__c
      |- |align="center" valign="middle" style="background-color:#eee;"|Schema.SObjectType | valign="top"|
  • Schema.SObjectType objType = obj.getSObjectType();
  • Schema.SObjectType objType = Custom__c.sObjectType;
  • Schema.SObjectType objType = objDesc.getSObjectType();

  • Custom__c obj = (Custom__c)objType.newSObject();
    |- |align="center" valign="middle" style="background-color:#eee;"|Schema.DescribeSObjectResult | valign="top"|
  • Schema.DescribeSObjectResult objDesc = objType.getDescribe();
  • Schema.DescribeSObjectResult objDesc = Custom__c.sObjectType.getDescribe();
  • Schema.DescribeSObjectResult objDesc = Schema.SObjectType.Custom__c;

  • String objDesc.getName()
  • String objDesc.getLabel()
  • String objDesc.getKeyPrefix()
  • List<Schema.ChildRelationship> objDesc.getChildRelationships()
    |- |align="center" valign="middle" style="background-color:#eee;"|Schema.SObjectField | valign="top"|
  • Schema.SObjectField field = fieldDesc.getSObjectField();
  • Schema.SObjectField field = Custom__c.Field__c;
  • Map<String, Schema.SObjectField> fieldAll = Schema.SObjectType.Custom__c.fields.getMap();
    • 표준 필드는 key에 namespace가 붙지 않습니다.
    • 사용자 정의 필드는 namespace가 다를 경우, key에 "NS__" 와 같은 형태의 namespace가 앞에 붙습니다.
  • 참고 문헌
    • Field Types
      |- |align="center" valign="middle" style="background-color:#eee;"|Schema.DescribeFieldResult | valign="top"|
  • Schema.DescribeFieldResult fieldDesc = field.getDescribe();
  • Schema.DescribeFieldResult fieldDesc = Custom__c.Field__c.getDescribe();
  • Schema.DescribeFieldResult fieldDesc = Schema.sObjectType.Custom__c.fields.Field__c;

  • String fieldDesc.getLabel();
  • String fieldDesc.getName();
  • Schema.DisplayType fieldDesc.getType();
  • List <Schema.PicklistEntry> fieldDesc.getPicklistValues();
  • Object fieldDesc.getDefaultValue();
  • Schema.SOAPType Enum
    • String, Integer, Double, Boolean, Date, Datetime, Time
    • ID, anytype, base64binary
  • 제공 함수
    • Integer getByteLength()
    • String getCalculatedFormula()
    • Schema.SObjectField getController()
    • Object getDefaultValue()
    • String getDefaultValueFormula()
    • Integer getDigits()
    • String getInlineHelpText()
    • String getLable()
    • Integer getLength
    • String getLocalName()
    • String getName()
    • List<Schema.PicklistEntry> getPicklistValues()
    • Integer getPrecision()
    • List<Schema.SObjectType> getReferenctTo()
    • String getRelationshipName()
    • Integer getRelationShipOrder()
    • Integer getScale()
    • Schema.SoapType getSoapType()
    • Schema.SObjectField getSobjectField()
    • Schema.DisplayType getType()
    • Boolean isAccessible()
    • Boolean isAutoNumber()
    • Boolean isCalculated()
    • Boolean isCaseSEnsitive()
    • Boolean isCreateable()
    • Boolean isCustom()
    • Boolean isDefaultedOnCreate()
    • Boolean isDependentPicklist()
    • Boolean isDeprecatedAndHidden()
    • Boolean isExternalId()
    • Boolean isFilterable()
    • Boolean isHtmlFormatted()
    • Boolean isIdLookup()
    • Boolean isNameField()
    • Boolean isNamePointing()
    • Boolean isNillable()
    • Boolean isRestrictedPicklist()
    • Boolean isSortable()
    • Boolean isUnique()
    • Boolean isUpdateable()
    • Boolean isWriteRequiresMasterRead()
      |}
  • picklist entry
  • 제약 사항
    • 최대 100개의 fields 멤버를 사용할 수 있습니다.


Dynamic SOQL

  • 동적으로 데이터 읽기

    sObject item = Database.query(string_limit_1);
    List data = Database.query(string);

  • 동적으로 데이터 처리하는 샘플

    List data = null;
    Map columns = null;
    
    data = Database.query(strQuery);
    columns = data.getSObjectType().getDescribe().fields.getMap();
    for (sObject item : data) {
       for (String name : columns.keySet()) {
           string value = null;
    
           value = String.valueOf(item.get(name));
       }
    }

  • 참고 문헌


Dynamic Visualforce

  • 변수 : ., [‘’](‘~’.md)
  • Map<String, Schema.SobjectField> = Schema.SobjectType.Account.fields.getMap();
  • Schema.SobjectField
    • getDescribe().isAccessible(), isCustom()
  • Component.NameSpace.~
    • Component.Apex.OutputText
  • {!$ObjectType.Account.FieldSets.~}
    • Field : Label, Type, Required, FieldPath, DBRequired
  • sObject.put(, ~), get()
  • StandardController
  • StandardSetController
    • reset(), addFields(List)
  • Include
    • <apex:include pageName=“~” />
    • <apex:includeScript value=“{$Resource.~}” />
    • <apex:stylesheet value=“{$Resource.~}” />�
    • <apex:iframe src=“” height=“” width=“~” scrolling=“true” frameborder=“false” />


Managed Sharing


  • 공유 권한 : 소유자 -> 역할 -> 공유 설정 / 필드 접근성

  • User Managed Sharing

    • Access Level : None. Private, Read. Read Only, Edit. Read/Write, All. Full Access

    • 개체명__Share

    • Modify All Data" 권한이 있어야 사용 가능

      public class JobSharing {
       public Boolean manualShare(ID recordId, ID userOrGroup) {
           Job__Share share = new Job__Share();
      
           share.ParentId = recordId;
           share.UserOrGroup = userOrGroup;        //--- Job.Recruiter__c
           share.AccessLevel = ‘Read’;
           share.RowCause = Schema.Job__Share.RowCause.Manual;
           //--- 공유 이유가 Recruite일 경우 (사용자 정의 공유 이유)
           //--- share.RowCause = Schema.Job__Share.RowCause.Recruite__c;
           Database.insert(share);
       }
      }


JSONObject


apex-library의 JSONObject를 사용하여 JSON 데이터를 처리할 수 있습니다.

  • JSONObject Class

    • 생성자 : JSONObject(String source)
    • Key 확인
      Boolean has(String key)
      SET keys()
    • 데이터를 저장하는 함수
      JSONObject putOpt(String key, JSONObject.value value)
    • 데이터 읽어 오는 함수
      JSONObject.value  getValue(String key)
      Object  get(String key)
      Object  opt(String key)   //--- Default는 null을 반환
      

    String getString(String key) //--- Integer.valueOf(string), Date.valueOf(string) 등을 사용하여 다른 type으로 변환 가능

    Boolean getBoolean(String key) Boolean optBoolean(String key) //--- Default는 false Boolean optBoolean(String key, Boolean defaultValue) String valueToString()

    - 데이터 읽어 오는 함수의 응용

    JSONObject snbJson = new JSONObject(strJson); for (JSONObject.value jsonItem : snbJson.getValue('data').values) { JSONObject item = null;

    item = new JSONObject(jsonItem.valueToString()); } ```


  • JSONObject.value Class의 속성값

    JSONObject obj
    String str
    Integer num
    Double dnum
    Boolean bool
    List values

  • 참고 문헌


Apex Code 개발



Request

  • Apex Code에서
    ApexPages.currentPage().getParameters().get('id');
  • VisualForce Page에서
    {!$CurrentPage.parameters.cid}


Cookie는 일반적으로 도메인을 기준으로 설정이 됩니다. 세일즈포스닷컴은 CRM 서비스를 제공하는 URL과 Visualforce의 URL이 다르므로 서로 다른 도메인의 URL을 가지게 됩니다.

  • 세일즈포스닷컴의 URL 종류

  • Apex Code에서 Cookie 사용 방법

    • Apex Code에서 저장한 Cookie는 이름의 앞에 "apex__"가 자동으로 붙어서 처리가 됩니다.
      public class UtilCookie {
      public static String getCookie(String name) {
          Cookie cookie = null;
        
      cookie = ApexPages.currentPage().getCookies().get(name); if (cookie == null) { return null; } else { return cookie.getValue(); } }
      //--- 저장되는 Cookie명은 "apex__" + name 입니다. public static void setCookie(String name, String value) { Cookie cookie = null;
      cookie = new Cookie(name, value, null, -1, false); ApexPages.currentPage().setCookies(new Cookie[](.md){ cookie }); } }

  • JavaScript에서 Cookie 사용 방법



Session

사용자 세션을 활용하여 세션 정보를 관리하는 모듈을 작성 합니다.

  • Session의 종류

  • Session__c 개체 그림:Session.png


  • DaoSession

    public class DaoSession {
      public String sessionId {get; set;}
    
    public DaoSession(String argSessionId) { sessionId = argSessionId; } public String findData(String argName) { Session__c session = null;
    session = [SELECT Id, Name, SessionId__c, Name__c, Value__c, LastModifiedDate FROM Session__c WHERE SessionId__c = :sessionId AND Name__c = :argName LIMIT 1]; return session.Value__c; }
    public void insertData(String argName, String argValue) { Session__c session = null;
    session = new Session__c(); session.SessionId__c = sessionId; session.Name__c= argName; session.Value__c = argValue; insert session; }
    public void updateData(String argName, String argValue) { Session__c session = null;
    session = [SELECT Id, Name, SessionId__c, Name__c, Value__c, LastModifiedDate FROM Session__c WHERE SessionId__c = :sessionId AND Name__c = :argName LIMIT 1]; session.Value__c = argValue; update session; }
    public Void upsertData(String argName, String argValue) { Session__c session = null;
    try { session = [SELECT Id, Name, SessionId__c, Name__c, Value__c, LastModifiedDate FROM Session__c WHERE SessionId__c = :sessionId AND Name__c = :argName LIMIT 1]; } catch (Exception ex) { }
    if (session == null) { session = new Session__c(); session.SessionId__c = sessionId; session.Name__c= argName; session.Value__c = argValue; insert session; } else { session.Value__c = argValue; update session; } } public Void deleteData(String argName) { Session__c session = null;
    session = [SELECT Id, Name, SessionId__c, Name__c, Value__c, LastModifiedDate FROM Session__c WHERE SessionId__c = :sessionId AND Name__c = :argName LIMIT 1]; delete session; } }

  • MgrSession

    public class MgrSession {
      public DaoSession dao = null;
    
    public MgrSession() { dao = new DaoSession(UserInfo.getSessionId()); }
    public String getSession(String argName) { return dao.findData(argName); }
    public Void setSession(String argName, String argValue) { dao.upsertData(argName, argValue); } }

  • SchSession

    • "App 설정 -> 개발 -> Apex 클래스" 메뉴에서 "Apex 예약"에서 등록
    • "관리 설정 -> 모니터링 -> 예약된 작업"에서 등록된 작업을 조회
      global class SchSession implements Schedulable {
      global void execute(SchedulableContext sc) {
          BatSession batch = null;
        
      batch = new BatSession(); Database.executeBatch(batch); } }

  • BatSession

    global class BatSession implements Database.Batchable {
      global Database.QueryLocator start(Database.BatchableContext ctx) {
          Datetime tmpDate = null;
        
    tmpDate = Datetime.now(); tmpDate.addDays(-3); return Database.getQueryLocator([SELECT Id FROM Session__c WHERE CreatedDate < :tmpDate]); }
    global void execute(Database.BatchableContext ctx, List scope) { delete scope; }
    global void finish(Database.BatchableContext ctx) { } }


Config

  • ConfigSetting__c Custom Settings 그림:Forcecom config new.png


  • MgrConfig

    public class MgrConfig {
      public MgrConfig() {
      }
    
    public String getConfig(String argName) { ConfigSetting__c config = null;
    config = ConfigSetting__c.getValues(argName); return config.Value__c; } }

  • Config__c 개체 그림:Forcecom config.png


  • DaoConfig

    public  class DaoConfig {
      public static String CATEGORY = 'global';
    
    public DaoConfig() { } public String findData(String argCategory, String argName) { Config__c config = null;
    config = [SELECT Id, Name, Category__c, Name__c, Value__c FROM Config__c WHERE Category__c = :argCategory AND Name__c = :argName LIMIT 1]; return config.Value__c; }
    public String findData(String argName) { return findData(CATEGORY, argName); }
    public void insertData(String argCategory, String argName, String argValue) { Config__c config = null;
    config = new Config__c(); config.Category__c = argCategory; config.Name__c = argName; config.Value__c = argValue; insert config; }
    public void insertData(String argName, String argValue) { insertData(CATEGORY, argName, argValue); }
    public void updateData(String argCategory, String argName, String argValue) { Config__c config = null;
    config = [SELECT Id, Name, Category__c, Name__c, Value__c FROM Config__c WHERE Category__c = :argCategory AND Name__c = :argName LIMIT 1]; config.Value__c = argValue; update config; }
    public void updateData(String argName, String argValue) { updateData(CATEGORY, argName, argValue); }
    public Void upsertData(String argCategory, String argName, String argValue) { Config__c config = null;
    try { config = [SELECT Id, Name, Category__c, Name__c, Value__c FROM Config__c WHERE Category__c = :argCategory AND Name__c = :argName LIMIT 1]; } catch (Exception ex) { }
    if (config == null) { config = new Config__c(); config.Category__c= argCategory; config.Name__c= argName; config.Value__c = argValue; insert config; } else { config.Value__c = argValue; update config; } } public Void upsertData(String argName, String argValue) { upsertData(CATEGORY, argName, argValue); } public Void deleteData(String argCategory, String argName) { Config__c config = null;
    config = [SELECT Id, Name, Category__c, Name__c, Value__c FROM Config__c WHERE Category__c = :argCategory AND Name__c = :argName LIMIT 1]; delete config; }
    public Void deleteData(String argName) { deleteData(CATEGORY, argName); } }

  • MgrConfig

    public class MgrConfig {
      public DaoConfig dao = null;
    
    public MgrConfig() { dao = new DaoConfig(); }
    public String getConfig(String argCategory, String argName) { return dao.findData(argCategory, argName); }
    public String getConfig(String argName) { return dao.findData(argName); }
    public Void setConfig(String argCategory, String argName, String argValue) { dao.upsertData(argCategory, argName, argValue); }
    public Void setConfig(String argName, String argValue) { dao.upsertData(argName, argValue); } }


참고 문헌



- [세일즈포스닷컴](http://www.salesforce.com/)
- [AppExchange](http://www.salesforce.com/appexchange/)
- [SuccessForce](http://success.salesforce.com/)
- [Developer.force.com](http://developer.force.com/)

- [An Introduction to Apex Code Test Methods](http://wiki.developerforce.com/index.php/An_Introduction_to_Apex_Code_Test_Methods)

- [Development Lifecycle Guide](http://www.peteyg.com/SFDC/DevForce/dev_lifecycle/index_Left.htm)

지원 업체



{{지원업체}} [[Category:Salesforce|Category:Salesforce]]
[[Category:Cloud|Category:Cloud]]
분류: [CRM](분류_CRM.md)
공유하기