0

I have a weird issue that I'm not even sure how to describe completely. Basically, in my trigger handler class I'm using a set of set of Ids to compare records so only the new records not contained in the set will be inserted. The code only works correctly if I debug the set.

Basically, the set is a list of ids that I compare with fields from the trigger.new records.

What do you think the debug statement is doing to cause the code to run correctly over when it's not inserted?

Here's an excerpt of the code in question.

The Set I'm creating.

private Set<Set<Id>> getCurrentAssociationSet(Set<Id> offeringSet) {
    Set<Set<Id>> studentAdvisorSet = new Set<Set<Id>>();
    List<Student_Advisor__c> currentAssociations = [SELECT Id, Academic_Offering__c, Advisor__c, Student__c FROM Student_Advisor__c WHERE Academic_Offering__c IN :offeringSet];
    if(!currentAssociations.isEmpty()) {
        for(Student_Advisor__c sa: currentAssociations) {
            studentAdvisorSet.add(
                new Set<Id>{
                    sa.Academic_Offering__c,
                    sa.Advisor__c,
                    sa.Student__c
                }
            );
        }
    }
    return studentAdvisorSet;
}

Usage

Set<Set<Id>> studentAdvisorSet = getCurrentAssociationSet(offeringSet);
/*
If this debug line is removed when I checked the set later 
it doesn't have the expected values
*/ 
System.debug(studentAdvisorSet);
// Loop through offerings and set the student list and advisor map
        for(Academic_Offering__c ao: offerings) {
            for(Academic_Plan__c ap: ao.Academic_Plans__r) {
                // Check for student record type and that the Contact persona is a student
                if(ap.RecordTypeId == STUDENT_RECORD_TYPE_ID && isStudent(ap.Contact__r.Active_Personas__c)) {
                    students.add(ap);
                }   
                // Check for advisor record type and that the Contact persona is an instructor
                if(ap.RecordTypeId == ADVISOR_RECORD_TYPE_ID && isAdvisor(ap.Contact__r.Active_Personas__c)) {
                    advisorMap.put(ap.Academic_Offering__c, ap);
                }
            }
        }
        // Loop through the students to match with advisor and set offering
        for(Academic_Plan__c student: students) {
            // Get the advisor plan record by offering
            Academic_Plan__c advisor = advisorMap.get(student.Academic_Offering__c);
            // Check if advisor is null and if there is a match between student and advisor offering
            if (advisor != null && student.Academic_Offering__c == advisor.Academic_Offering__c) {
                // Set the matched set
                Set<Id> matchedOffering = new Set<Id>{
                    student.Academic_Offering__c, 
                    advisor.Contact__c, 
                    student.Contact__c
                };
                // Compare match set to current student advisor records and add new record if there is not a match                   
                if(studentAdvisorSet.isEmpty()) {
                    associations.add(
                        new Student_Advisor__c(
                            Academic_Offering__c = student.Academic_Offering__c,
                            Student__c = student.Contact__c,
                            Advisor__c = advisor.Contact__c,
                            Type__c = 'Faculty'
                        )
                    );     
                } 
                /*
                If the set is not empty check for existing so we don't create   duplicates 
                (If I remove the debug statement the set comparion does nothing and will create duplicates)
                */
                else if (!studentAdvisorSet.contains(matchedOffering)) {
                    associations.add(
                        new Student_Advisor__c(
                            Academic_Offering__c = student.Academic_Offering__c,
                            Student__c = student.Contact__c,
                            Advisor__c = advisor.Contact__c,
                            Type__c = 'Faculty'
                        )
                    );    
                }
            }

This Also happens in the batch class as well. If I don't debug studentAdvisorSet I get duplicates. See below.

global class LRMStudentAdvisorBatch implements Database.Batchable<Student_Advisor__c> {

// Academic offering Iterable for batch processing
global Iterable<Student_Advisor__c> start(Database.BatchableContext info){ 
    return new ProcessStudentAdvisorAssociation(); 
}
// Execute the batch
global void execute(Database.batchableContext info, List<Student_Advisor__c> scope){ 
    // This should not be empty, but in case check
    if(!scope.isEmpty()) {
        try { insert scope; } catch (Exception e) {}
    }
}    
// Nothing to post process
global void finish(Database.BatchableContext BC){}
/**
 * Custom Iteration class to handle batch Student_Advisor__c inserts
 */
global class StudentAdvisorIterable implements Iterator<Student_Advisor__c> {

    // List to iterate
    List<Student_Advisor__c> associations {get; set;}    
    // Iterator
    Integer i {get; set;}
    // Academic offerings to query
    private List <Academic_Offering__c> offerings;
    // Set of academic plan RecordTypeIds
    private Set<Id> recordTypeIds;
    // Set the student RecordTypeId
    private final Id STUDENT_RECORD_TYPE_ID = SObjectType.Academic_Plan__c.getRecordTypeInfosByName().get('Student').getRecordTypeId();
    // Set the advisor RecordTypeId
    private final Id ADVISOR_RECORD_TYPE_ID = SObjectType.Academic_Plan__c.getRecordTypeInfosByName().get('Educator').getRecordTypeId();

    // Constructor
    public StudentAdvisorIterable() {
        associations = new List<Student_Advisor__c>();
        // Set of academic plan record types to query
        recordTypeIds = new Set<Id>{
            STUDENT_RECORD_TYPE_ID,
            ADVISOR_RECORD_TYPE_ID
        };
        offerings = getOfferings();         
        // Set of Ids with offering, student, and advisor
        Set<Set<Id>> studentAdvisorSet = new Set<Set<Id>>();
        // List of students with academic plans
        List<Academic_Plan__c> students = new List<Academic_Plan__c>();
        // Map to match advisor and student accademic offerings
        Map<Id, Academic_Plan__c> advisorMap = new Map<Id, Academic_Plan__c>();
        // If there any existing student advisor records loop through and them to the set to check later
        for (Student_Advisor__c sa: [SELECT Id, Academic_Offering__c, Advisor__c, Student__c FROM Student_Advisor__c]) {
            studentAdvisorSet.add(
                new Set<Id>{
                    sa.Academic_Offering__c, 
                    sa.Advisor__c, 
                    sa.Student__c
                }
            );
        }
        /*
        If this debug line is removed when I checked the set later 
        it doesn't have the expected values
        */ 
        System.debug(studentAdvisorSet);
        // Loop through offerings and plans set student list and advisor map
        for(Academic_Offering__c ac: offerings) {
            for(Academic_Plan__c ap: ac.Academic_Plans__r) {
                if(ap.RecordTypeId == STUDENT_RECORD_TYPE_ID && isStudent(ap.Contact__r.Active_Personas__c)) {
                    students.add(ap);
                }   
                if(ap.RecordTypeId == ADVISOR_RECORD_TYPE_ID && isAdvisor(ap.Contact__r.Active_Personas__c)) {
                    advisorMap.put(ap.Academic_Offering__c, ap);
                }
            }
        }    
        // Loop through the student list and check for matches with advisor offerings
        for(Academic_Plan__c student: students) {
            // Get the advisor plan record by offering
            Academic_Plan__c advisor = advisorMap.get(student.Academic_Offering__c);
            // Check if advisor is null and if there is a match between student and advisor offering
            if (advisor != null && student.Academic_Offering__c == advisor.Academic_Offering__c) {
                // Set the matched set
                Set<Id> matchedOffering = new Set<Id>{
                    student.Academic_Offering__c, 
                    advisor.Contact__c, 
                    student.Contact__c
                };
                // Compare match set to current student advisor records and add new record if there is not a match
                if(studentAdvisorSet.isEmpty()) {
                    associations.add(
                        new Student_Advisor__c(
                            Academic_Offering__c = student.Academic_Offering__c,
                            Student__c = student.Contact__c,
                            Advisor__c = advisor.Contact__c
                        )
                    );     
                } 
                else if (!studentAdvisorSet.contains(matchedOffering)) {
                    associations.add(
                        new Student_Advisor__c(
                            Academic_Offering__c = student.Academic_Offering__c,
                            Student__c = student.Contact__c,
                            Advisor__c = advisor.Contact__c
                        )
                    );    
                }
            }
        }
        i = 0;
    }
    /**
     * Gets a list of academic current academic offerings and their related plans
     * @return             List<Academic_Offering__c>
     */
    private List<Academic_Offering__c> getOfferings() {
        return [
            SELECT Id, 
                   (SELECT Id, 
                           RecordType.Name, 
                           Academic_Offering__c, 
                           Contact__c,
                           Contact__r.Active_Personas__c
                    FROM   Academic_Plans__r 
                    WHERE  RecordTypeId IN :recordTypeIds 
                           AND Contact__c != null
                           AND Contact__r.Active_Personas__c != null) 
            FROM   Academic_Offering__c 
            WHERE  Id IN (SELECT Academic_Offering__c 
                          FROM   Academic_Plan__c) 
        ];
    }      
    /**
     * Checks the Active persona multi-picklist values to see it contains 'Student'
     * @param  persona The Active Persona picklist value
     * @return         Boolean
     */
    private Boolean isStudent(String persona) {
        if (String.isNotBlank(persona)) {
            Set<String> personaSet = new Set<String>(persona.Split(';'));
            return personaSet.contains('Student');
        } else {
            return false;
        }
    }
    /**
     * Checks the Active persona multi-picklist values to see it contains 'Instructor'
     * @param  persona The Active Persona picklist value
     * @return         Boolean
     */
    private Boolean isAdvisor(String persona) {
        if (String.isNotBlank(persona)) {
            Set<String> personaSet = new Set<String>(persona.Split(';'));
            return personaSet.contains('Instructor');
        } else {
            return false;
        }
    }
    // Check if there are more records to iterate
    global boolean hasNext(){ 
        if(i >= associations.size()) {
            return false; 
        } else {
            return true; 
        }
    }   
    // Next offering in interation
    global Student_Advisor__c next(){ 
        i++; 
        return associations[i-1]; 
    }        
}
// Set the iterable for the batch
global class ProcessStudentAdvisorAssociation implements Iterable<Student_Advisor__c>{
    global Iterator<Student_Advisor__c> Iterator(){
        return new StudentAdvisorIterable();
    }
}
  • Your description is quite unclear. Can you edit your post to include your code? – Adrian Larson Oct 21 '16 at 19:31
  • FYI, here is one case where debug settings changed the code executed but not in a way that violated the contract. – Keith C Oct 21 '16 at 19:42
  • Could it be a bracketing issue? If debug is put in wrong place below an IF without brackets it would cause the statement it bumped to always be executed. Although if debug is executed the bumped statement should have been executed. Just something to check in addition to the more complex issue posted by Adrian. – Eric Oct 21 '16 at 19:59
  • @AdrianLarson Added an excerpt of code. – Andrew L. Oct 22 '16 at 17:34
  • Can you post the code from: getCurrentAssociationSet - There may be something going on there that only returns values on the SECOND go around... – Eric Oct 22 '16 at 22:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.