2011-05-03 2 views
1

Salesforce.com의 Apex 프로그래밍 언어를 배우려고하고 있으며 Jason Ouellette가 저술 한 "Force.com 플랫폼 개발"책에서 나온 몇 가지 코드 예제를 보았습니다. 나는 여전히 기초를 배우고 있으므로 나와 함께 견뎌주십시오. 컨텍스트에서이 코드를 사용하려면 책 전체에 걸쳐있는 서비스 관리자 샘플 응용 프로그램이 있으며 타임 카드에 유효한 할당이 있는지 확인하기 위해 작성한 Apex 트리거 장치를 검사하고 있습니다. 과제는 특정 기간 동안 프로젝트에 자원이 배치되었음을 나타내는 기록입니다. 컨설턴트 (일명 자원)는 프로젝트 및 시간 동안 만 근무 시간 카드를 입력 할 수 있습니다. Resource_c는 Assignment_c 및 Timecard_c 개체의 부모입니다.Elementary Apex 트리거 논리 고장

그래서 여기에 트리거와 해당 정점 클래스에 대한 코드가 있습니다. 나는 그것의 논리를 이해하기 위해 그것을 한 줄 한 줄씩 주석을 달아서 시도하고있다. 그러나, 나는 아직도 여기에 몇 가지 기본을 놓치고있다, 이것을 해독하는 데 자유롭게 느끼십시오.

5-57 트리거 (Trigger)

trigger validateTimecard on Timecard__c (before insert, before update) { 
    TimecardManager.handleTimecardChange(Trigger.old, Trigger.new); 
    // TheApexClass.methodThatDoesWork(variable, variable) 
    // So there are 2 parameters which are 2 lists, Trigger.old and Trigger.new. 
    // Which means, when this method is called it needs these 2 lists 
    // to process it's block of code, right? 
    // Why are they called Trigger.old, Trigger.new? Does the order of variables   matter? 
} 

5-58 - Apex의 클래스 - 트리거를 대신하여 근무 시간 기록표를 검증하는 작업을 수행합니다.

public class TimecardManager { 
     public class TimecardException extends Exception {} 
     public static void handleTimecardChange(List<Timecard__c> oldTimecards, List<Timecard__c> newTimecards) { 

      // Identifying 2 lists of Timecards as parameters, oldTimecards and newTimecards 
      // within the class. How is this associated with the trigger parameters 
      // that were seen in the trigger above. Are they the same parameters with 
      // different names? Why are they named differently here? Is it better to 
      // write the trigger first, or the apex class first? 

      Set<ID> resourceIds = new Set<ID>(); // making a new set of primitive data type ID called resourceIds 

      for (Timecard__c timecard : newTimecards) { 
       // This for loop assigns the timecard variable record to the list of newTimecards 
       // and then executes the block of code below for each. 
       // The purpose of this is to identify all the resources that have timecards. 
       resourceIds.add(timecard.Resource__c); 

       // It does this by adding the Timecard_c's relationship ID from each parent record Resource_c to the resourceIds set. 
       // For clarification, Resource_c is a parent to both 
       // Assignment_c and Timecard_c objects. Within the Timecard_c object, Resource_c 
       // is a Master-Detail data type. Is there a relationship ID that is created 
       // for the relationship between Resource_c and Timecard_c? 
      } 

      List<Assignment__c> assignments = [ SELECT Id, Start_Date__c, End_Date__c, Resource__c FROM Assignment__c WHERE Resource__c IN :resourceIds ]; 

      // The purpose of this is to make a list of selected information from Assignments_c that have resources with timecards. 

      if (assignments.size() == 0) { 
       // If there isn't a Resource_c from Assignments_c that matches a Resource_c that has a Timecard_c, 
       throw new TimecardException('No assignments'); // then an exception is thrown. 
      } 

      Boolean hasAssignment; // creation of a new Boolean variable 
      for (Timecard__c timecard : newTimecards) { // so for every newTimecards records, 
       hasAssignment = false; // set Boolean to false as default, 
       for (Assignment__c assignment : assignments) { // check through the assignments list 
        if (assignment.Resource__c == timecard.Resource__c && // to make sure the Resources match, 
         timecard.Week_Ending__c - 6 >= assignment.Start_Date__c && // the end of the timecard is greater than the assignment's start date, 
         timecard.Week_Ending__c <= assignment.End_Date__c) { // and the end of the timecard is before the assignment's end date. 
          hasAssignment = true; // if these all 3 are correct, than the Timecard does in fact have an assignment. 
          break; // exits the loop 
        } 
       } 
       if (!hasAssignment) { // if hasAssignment is false then, 
        timecard.addError('No assignment for resource ' + // display an error message 
        timecard.Resource__c + ', week ending ' + 
        timecard.Week_Ending__c); 
       } 
      } 
     } 
    } 

감사합니다.

답변

2

1. Trigger.old/Trigger.new 란 무엇입니까? Trigger.new/Trigger.old는 트리거 컨텍스트에서 실행되는 모든 Apex 코드에서 사용할 수있는 정적 컬렉션입니다. 즉 트리거 또는 트리거에서 호출 한 모든 클래스에서 직접 실행됩니다.

Apex도 sobject 목록 대신 Map을 반환하는 Trigger.newMap 및 Trigger.oldMap을 제공합니다.

이러한 컬렉션의 유일한 목적은 이벤트가 "삽입 전"또는 "삽입 후"인 경우와 같이 트리거가 실행되는 이벤트에 따라 다릅니다. Trigger.old는 중요하지 않으므로 사용할 수 없습니다. Trigger.old는 항상 레코드 업데이트 중 수행 된 변경 사항을 비교하는 데 사용됩니다.

2. 주문 사항을합니까 : 당신이 첫 번째 인수로 Trigger.old을 통과해야하므로 그것은 단지, 새로운 전에 오래된 일한를 기대하는 방법 "handleTimecardChange"로,이 타임 카드 관리자의 경우에, 당신의 논리에 따라 달라집니다.

3. 목록이 필요합니까? : 다시 말하지만 구현에 따라 Trigger.new /old는 트리거가 작성된 sobject가있는 목록을 반환합니다. Trigger.new/old를 인수로 전달하는 것은 아니지만 Apex 클래스를 Trigger 컨텍스트와 분리하여 유지하는 것이 좋습니다. 단위 테스트가 더 쉬워집니다.

도움이 되었으면, 일반적으로 Apex 언어에 대한 깊은 이해를 위해 먼저 Apex 언어 참조를 읽어보십시오. 제이슨 오 (Jason O.)의 책은 굉장하지만, 먼저 기본을 이해해야합니다. 다음은 에이펙스 언어 참조에 대한 링크입니다 : http://www.salesforce.com/us/developer/docs/apexcode/index.htm

0

트리거의 new, newMap, oldoldMap 당신이 추적하는 DML의 유형에 따라에서만 사용할 수 있습니다.

DELETE = 만 오래

INSERT = 만 새로운

UPDATE = 구 모두 가능하며 새로운 가능 가능하며, 목록의 항목의 순서와 일치한다 (예를 들면 새로운 [1] [이전 대체 1]). new에는 새 값이 포함되고 old에는 이전 값이 포함되어 있지만 (ID는 항상 동일 함) 특정 필드가 변경되었는지 비교하고 확인할 수 있습니다.

항상 new/old를 다중 항목 목록 (또는 * Map의지도)으로 취급해야합니다. 정규 SQL의 경우 일괄 처리 업데이트 작업은 한 번만 이전 행과 새 행의 목록을 제공하는 트리거를 호출하므로 하나의 항목 만 있다고 가정하지 마십시오. 모든 변경 행을 반복하고 보유하고있는 논리를 적용해야합니다.

이 예제에서 oldTimecards 매개 변수는 정적 메서드에서 전혀 사용되지 않으므로 전혀 참조 할 필요가 없습니다. SF를 사용하지 않고도 SF가 전체 목록을 작성해야했기 때문에 SF가 전체 목록을 작성해야했기 때문에 자원을 낭비했습니다. 트리거 코드와 지원 클래스 코드를 제어하면 필요한 것만 전달합니다.