2

This is a question which I really can't find an answer to. In a trigger before insert or update, I like to compare 4 field values from the object named Calculation__c with 4 field values of Driver_Course__c.

The fields on Calculation__c are named:

  • Course__c
  • Cup__c
  • Tour__c
  • Driver__c

Those 4 fields i like to compare with the following fields of the object Driver_Course__c:

  • Course__c
  • Course__r.Cup__c
  • Course__r.Cup__r.Tour__c
  • Driver__c

With nested for loops it's easy, but I don't want to run into any governor limits, which I will regarding my test class, which gives me the error: CPU Limits exceeds.

I know how to get the data prepared for matching, but the matching itself I really dont know what to do. There is no exact field to match both objects. So it's purely those 4 fields which have to match. After removing and adding stuff this is what i got:

public without sharing class AutoFillCalculations {
public static void FillOut(List<Calculation__c> calcList) {

    // Id nodig van Course
    Set<Id> courseIdSet = new Set<Id>();
    // Id nodig van Cup
    Set<Id> cupIdSet = new Set<Id>();
    //Id nodig van Tour
    Set<Id> tourIdSet = new Set<Id>();
    // Id nodig van Driver
    Set<Id> driverIdSet = new Set<Id>();
    Map<Id, Driver_Course__c> driverCourseById = new Map<Id, Driver_Course__c>();


    // Add the Ids to the sets
    for(Calculation__c calc : calcList){
        courseIdSet.add(calc.Course__c);
        cupIdSet.add(calc.Cup__c);
        tourIdSet.add(calc.Tour__c);
        driverIdSet.add(calc.Driver__c);

    }

    // Query  ids met junction object Driver Course

    for(Driver_Course__c driverCourse : [SELECT Id, Driver__c, Course__c, Course__r.Cup__c, Course__r.Cup__r.Tour__c 
                                           FROM Driver_Course__c 
                                          WHERE Course__c IN :courseIdSet
                                            AND Course__r.Cup__c IN :cupIdSet
                                            AND Course__r.Cup__r.Tour__c IN :tourIdSet
                                            AND Driver__c IN :driverIdSet]){

        for(Calculation__c calc : calcList){

            If(driverCourse.Course__c == calc.Course__c &&
            driverCourse.Course__r.Cup__c == calc.Cup__c &&
            driverCourse.Course__r.Cup__r.Tour__c == calc.Tour__c &&
            driverCourse.Driver__c == calc.Driver__c){

                calc.Driver_Course__c = driverCourse.Id;
                //calcUpdateList.add(calc);
            }

        }

    }
}

}

4
  • I'm looking into it, but I'm quite new to coding so it's not 100% understandable. Could you help me out with my code so I can understand it a bit better please?
    – eazy4me
    Commented Mar 29, 2020 at 16:39
  • I get everything from your map collections post till the moment you need to compare the Map with object array to the OpportunityLineItem. I'm not sure how I can compare the object array to my Calculation__c iterated loop.
    – eazy4me
    Commented Mar 29, 2020 at 16:55
  • 1
    Simply pick out the equivalent field values and use this to populate a new object array used in calling the map's get to find the object to which this one matches.
    – Phil W
    Commented Mar 29, 2020 at 17:00
  • I got it working! Thanks man!! Really much appreciated :)
    – eazy4me
    Commented Mar 29, 2020 at 17:01

2 Answers 2

5

This is a pretty standard "you need a map" scenario.

Map<Calculation__c, List<Calculation__c>> calcs = new Map<Calculation__c, List<Calculation__c>>();
for(Calculation__c calc : calcList){
    courseIdSet.add(calc.Course__c);
    cupIdSet.add(calc.Cup__c);
    tourIdSet.add(calc.Tour__c);
    driverIdSet.add(calc.Driver__c);
    Calculation__c key = new Calculation__c(Course__c=calc.Course__c, Cup__c=calc.Cup__c, Tour__c=calc.Tour__c,Driver__c=calc.Driver__c);
    Calculation__c[] temp = calcs.get(key);
    if(temp == null) {
        calcs.put(key, temp = new Calculation__c[0]);
    }
    temp.add(calc);
}

...

    for(Calculation__c calc : calcList){
    Calculation__c key = new Calculation__c(Course__c=calc.Course__c, Cup__c=calc.Course__r.Cup__c, Tour__c=calc.Course__r.Cup__r.Tour__c,Driver__c=calc.Driver__c);
        for(Calculation__c temp: calcs.get(key)) {
             // rest of logic //
3
  • This is my first month of developing, so I'm pretty new to everything related to programming. I knew maps but i never knew you could use them like you do. I will test it now :) When it works I will mark your answer as the answer. Thanks for the help man! Really much appreciated
    – eazy4me
    Commented Mar 29, 2020 at 16:27
  • I'm looking through your code, but I need the Id from the Driver_Course__c object which matches all 4 fields named in my original question on the Calculation__c record and put that Driver_Course__c.Id into the Driver_Course__c field on the Calculation__c record. Am i missing something?
    – eazy4me
    Commented Mar 29, 2020 at 16:32
  • Thanks for your help. I got it solved by Phil W post :)
    – eazy4me
    Commented Mar 29, 2020 at 17:02
-1

Have you thought about the possibility of creating a formula field on driver course that would be a concatenation of Course__c + Course__r.Cup__c + Course__r.Cup__r.Tour__c + Driver__c.

This way you could concat directly the field on your initial loop and query for this new formula field. If you generate a map, the result would be having one less iteration.

Let me know if the provided answer was of help.

map<String, Calculation__c> keyToCalculation = new map<String, Calculation__c>(); for(Calculation__c calc : calcList){ String key = calc.Course__c + calc.Cup__c + calc.Tour__c+ calc.Driver__c; keyToCalculation.put(key, calc); } for(Driver_Course__c driverCourse : [SELECT Id, Driver__c, Course__c, Course__r.Cup__c, Course__r.Cup__r.Tour__c FROM Driver_Course__c WHERE FormulaField IN :keyToCalculation.keyset()]{ if(keyToCalculation.containsKey(driverCourse.FormulaField)){ keyToCalculation.get(driverCourse.FormulaField).Driver_Course__c = driverCourse.Id; } }

4
  • String concatenation is slow. Far, far better to use the approach I have outlined in this answer
    – Phil W
    Commented Mar 29, 2020 at 15:46
  • How is he going to query for the Driver_Course__c using your approach. If he continue doing the query he was doing before the query will bring results that will not meet the desired criteria resulting in unnecesarry items in the collection being looped. Commented Mar 29, 2020 at 15:54
  • Exactly like he already does since the map concept doesn't rely on the means to query the objects to be processed. The formula field approach can certainly reduce the data returned from the query but I suggest you consider that these are not actually stored in the DB and are calculated at the time of querying.
    – Phil W
    Commented Mar 29, 2020 at 16:44
  • take a look at developer.salesforce.com/blogs/engineering/2013/03/…
    – Phil W
    Commented Mar 29, 2020 at 17:07

Not the answer you're looking for? Browse other questions tagged .