function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Vijay Zutshi 3Vijay Zutshi 3 

Trigger that rejects double booking not working

Hi,

I have 3 custome objects
1. Session - Fileds(Date, Description, Level, Session Name

2. Session Speaker (Junction object) has following fields:-
* Session - Master detail(Session)
* Session Speaker Number - auto number
* Speaker - Master Detail(Speaker)

3. Speaker- fields (Owner and Speaker number)

I have written a trigger to not allowing double bookings of Sessions but it is not working properly. The conflict variable does not pull up any record that are conflicting. My trigger is as follows:-

//Trigger to detect double booking
//for the session speaker
trigger rejectDoubleBooking on Session_Speaker__c (before insert, before update) {
    LIST<Session_Speaker__c> speakers = new LIST<Session_Speaker__c>();
    SET<ID> speakerId = new SET<ID>();
    LIST<Session__c> allSessions = new LIST<session__c>();    
    for(Session_Speaker__c sessionSpeaker : trigger.new) {
    speakerId.add(sessionSpeaker.Session__c);
        speakers.add(sessionSpeaker);
        system.debug('speakerId' + speakerId);
    system.debug('sessionspeaker' + sessionSpeaker); 
        system.debug('speakers' + speakers);
    }
    LIST<Session__c> ses = [SELECT ID, Session_Date__c 
                            FROM Session__c
                            WHERE Id =:speakerId];
   system.debug('ses' + ses); 
    
    LIST<Session_Speaker__c> conflicts = [SELECT Id
                                             FROM Session_Speaker__c
                                            WHERE Speaker__c =:speakerId
                                          AND Session__r.Session_Date__c =:ses];
    system.debug('conflicts' + conflicts);
       
         //If conflicts exist, add an error (reject the database operation)
            if(!conflicts.isEmpty()){
            //sessionSpeaker.addError('The speaker is already booked at that time');           
        }
    //}

}

Please help as I am stuck.

Thanks
Vijay
Ashish Singh SFDCAshish Singh SFDC
Hi Vijay,

If you want to avoid duplicate in Junction Object then you should create a Text Field with the name External Id and this field should be marked as required, External Id and Unique. This will ensure that in this new Text Field duplicate entries cannot exist and are always a required field. Then you need to make sure whenever a new record is inserted or update that field should be populated with the combination of SessionId and the SpeakerId. This approach will ensure data integrity and will be more cleaner. You can use before trigger to populate the value.



However, as per your question, I'm writing down a sample code that you can refine as it's something I'm directly writing in the forum and is not tested. So you will have to optimize the code and may be the logic as well.
 
trigger rejectDoubleBooking on Session_Speaker__c (before insert, before update) {

   
//First get all the sessionId and the speaker that are getting inserted or updated 
for(Session_Speaker__c sessionSpeakerRecord:Trigger.New)
   {
       Set<Id> sessionId = new Set<Id>();
       Set<Id> speakerId = new Set<Id>();
        if(sessionSpeakerRecord.Session__c!='' && sessionSpeakerRecord.Speaker__c!='')
        {
            sessionId.add(sessionSpeakerRecord.Session__c);
            sessionId.add(sessionSpeakerRecord.Speaker__c);
        }
   }

// Query all the existing Junction Object Record which involves all Session and Speaker
List<Session_Speaker__c> existingSessions = [SELECT Session__c, Speaker__c FROM Session_Speaker__c WHERE Session__c IN:sessionId OR Speaker__c IN:speakerId];

//Create a temp map from the above query variable which will hold combination of SessionID and speakerId for ex: 00121121121212__00232121223121 as key and value. This will act as identifier for comparision with the original for Loop

   Map<String,String> tempExternalIdMap = new Map<String,String>();
   for (Session_Speaker__c existingSpeakerSession : existingSessions) 
   {
       if(existingSpeakerSession.Session__c!='' && existingSpeakerSession.Speaker__c!='')
        {
            String sessionAndSpeakerId = existingSpeakerSession.Session__c+'__'+existingSpeakerSession.Speaker__c;
            tempExternalIdMap.put(sessionAndSpeakerId,sessionAndSpeakerId);
        }
   }


// We need to loop again with the original context variable and create again a temporary external id in the format sessionId and speakerId ex 00121121121212__00232121223121 and then check if the Map you created in previous step has this value. If yes, add error Message.
    for(Session_Speaker__c sessionSpeakerForError:Trigger.New)
   {
        if(sessionSpeakerForError.Session__c!='' && sessionSpeakerForError.Speaker__c!='')
        {
            String sessionAndSpeakerIdExt = sessionSpeakerForError.Session__c+'__'+sessionSpeakerForError.Speaker__c;

            if(externalIdMap.coontainsKey(sessionAndSpeakerIdExt))
            {
                sessionSpeakerForError.addError('Speaker already exists for the Session');
            }
        }
   }

}

Thanks,
Ashish Singh.