1

Salesforce.comのApexプログラミング言語を学習しようとしています。ここに、JasonOuelletteの著書「DevelopmentwiththeForce.comPlatform」からのコードの例があります。私はまだ基​​本を学んでいるので、我慢してください。このコードをコンテキストに入れるために、本全体に渡るServices Managerサンプルアプリケーションがあり、タイムカードに有効な割り当てがあることを確認するために作成されたApexトリガーデバイスを調べています。割り当ては、リソースが特定の期間プロジェクトに配置されていることを示すレコードです。コンサルタント(別名リソース)は、プロジェクトと彼または彼女が作業を許可されている期間についてのみタイムカードを入力できます。Resource_cは、Assignment_cオブジェクトとTimecard_cオブジェクトの両方の親です。

これが、トリガーと対応するapexクラスに対して提供されるコードです。私はそれを分解し、その論理を理解するために1行ずつコメント/質問しようとしています。しかし、私はまだここでいくつかの基本を欠いています、私がこれを解読するのを手伝ってください。

5-57トリガー

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);
                }
            }
        }
    }

ご協力ありがとうございました。

4

2 に答える 2

2

1. Trigger.old/Trigger.newとは:?

Trigger.new / Trigger.oldは、Triggerコンテキストで実行されているApexコードで使用できる静的コレクションです。つまり、トリガーで直接起動するか、Triggerによって呼び出されるクラスで起動します。

Apexは、sobjectリストの代わりにMapを返すTrigger.newMapとTrigger.oldMapも提供します。

これらのコレクションの唯一の目的は、トリガーが起動されるイベントによって異なります。たとえば、イベントが「挿入前」または「挿入後」の場合、Trigger.oldは重要ではないため、使用できません。Trigger.oldは、レコードの更新中に行われた変更を比較するために常に使用されます。

2.順序は重要ですか:このタイムカードマネージャーの場合、メソッド "handleTimecardChange"は新しい前に古いタイムカードを予期するため、ロジックにのみ依存します。したがって、最初の引数としてTrigger.oldを渡す必要があります。

3.リストにする必要がありますか?:これも実装によって異なりますが、Trigger.new / oldは、トリガーが書き込まれるリストを返します。Trigger.new / oldを引数として渡すことも必須ではありませんが、ApexクラスをTriggerコンテキストから切り離しておくことをお勧めします。ユニットテストが簡単になります。

これがお役に立てば幸いです。最初にApex言語リファレンスを読んで、Apex言語全般についてより深く理解してください。Jason O.の本は素晴らしいですが、最初に基本を理解する必要があります。Apex言語リファレンスへのリンクは次のとおりです:http://www.salesforce.com/us/developer/docs/apexcode/index.htm

于 2011-05-04T09:06:27.680 に答える
0

トリガーの、、、newおよびはnewMap、追跡しているDMLのタイプに応じてのみ使用できます。oldoldMap

DELETE=古いものだけが利用可能です

INSERT=新しいものだけが利用可能です

UPDATE =古いものと新しいものの両方が利用可能であり、リスト内のエントリの順序が一致しています(たとえば、new[1]がold[1]を置き換えます)。newには新しい値が含まれ、oldには古い値が含まれるため(ただし、IDは常に同じです)、特定のフィールドが変更されているかどうかを比較および確認できます。

常に新しい/古いものをマルチエントリリスト(または* Mapのマップ)として扱う必要があります。通常のSQLでは、バッチ更新操作は、古い行と新しい行のリストを提供したときにのみトリガーを呼び出すため、エントリが1つだけであると想定しないでください。変更されたすべての行を繰り返し処理し、使用しているロジックを適用する必要があります。

この例では、oldTimecardsパラメーターは静的メソッドでまったく使用されていないため、参照する必要もまったくありませんでした。SFは、使用しなくても古いリスト全体を作成する必要があったため、おそらくリソースも無駄になりました(ただし、最適化されているかどうかはわかりません)。トリガーコードとサポートクラスコードの両方を制御するため、必要なものだけを渡します。

于 2011-05-04T10:59:43.523 に答える