I am in a very peculiar situation. I have a trigger for after insert and it works by assigning starting dateTime and endingDate time to a user. if the time overlaps it throws an error. but somehow when multiple users click the save button together multiple records are saved for the same start and end time. How can I handle this situation? Following is the code for after insert

  public class EventDateTimeWrapper {
    Datetime startDateTime;
    DateTime endDateTime;
    Id evId;
     public EventDateTimeWrapper(DateTime stDt, DateTime endDt, Id eId){
         startDateTime = stDt;
         endDateTime = endDt;
         evId = eId;

public static void processAfterInsertEvent( Map<Id, Event> newEvMap){

    Set<Id> ownerIds = new Set<Id>();
    Set<Date> dateNew = new Set<Date>();
    Map<Id,Set<EventDateTimeWrapper>> OwnerTimeMap = new Map<Id,Set<EventDateTimeWrapper>>();       

    for( Event evNew: newEvMap.values() ){
        if( !String.isBlank(evNew.Appointment_Type__c) ){
            system.debug(' ### New Event available');
            ownerIds.add( evNew.OwnerId );
            system.debug('owner id is'+evNew.OwnerId);
            Set<EventDateTimeWrapper> evDateTimeMapper = new Set<EventDateTimeWrapper>();
            if( OwnerTimeMap != null && OwnerTimeMap.containsKey(evNew.OwnerId) ){
                evDateTimeMapper = OwnerTimeMap.get(evNew.OwnerId);
                system.debug('### evDateTimeMapper populated with same rep');                                     
            evDateTimeMapper.add( new EventDateTimeWrapper(evNew.StartDateTime,evNew.endDateTime, evNew.Id) );
            OwnerTimeMap.put(evNew.OwnerId, evDateTimeMapper);

    system.debug('### OwnerTimeMap: '+OwnerTimeMap);

    for( Event evExist: [SELECT StartDateTime, EndDateTime, OwnerId FROM Event WHERE OwnerId In :ownerIds 
                               AND DAY_ONLY(StartDateTime) IN :dateNew
                               AND Status__c <> :EventManager.STATUS_CANCELED
                               AND ShowAs <> :EventManager.SHOW_AS_FREE
                               AND ID NOT IN :newEvMap.keySet()]){
        if(OwnerTimeMap != null && OwnerTimeMap.containsKey(evExist.OwnerId)){
            system.debug('### Old events for OwnerId found');
            Boolean isError = false;
            List<EventDateTimeWrapper> evDateTimeMapper = new List<EventDateTimeWrapper>();
            evDateTimeMapper.addAll( OwnerTimeMap.get(evExist.OwnerId) );
            Integer counter = evDateTimeMapper.size();
            while(!isError && counter >= 1){
                counter --;
                EventDateTimeWrapper evWrapper = evDateTimeMapper[counter];
                system.debug('### evWrapper: '+ evWrapper);
                if((checkForMaximumStartDate(evExist.StartDateTime,evWrapper.startDateTime) < checkForMinimumEndDate(evExist.EndDateTime,evWrapper.endDateTime) ) || (evExist.StartDateTime == evWrapper.startDateTime && evExist.EndDateTime == evWrapper.endDateTime) ) {
                    System.debug('### Event clash');
                    isError = true;
                    Event eObj = newEvMap.get(evWrapper.evId);
                    eObj.addError('same time');


You need to handle this logic before insert. See addError usage here:


When used on Trigger.new in before insert and before update triggers, and on Trigger.old in before delete triggers, the error message is displayed in the application interface.

However, I think the real problem is in this line:

evExist.StartDateTime,evWrapper.startDateTime) < checkForMinimumEndDate(evExist.EndDateTime,evWrapper.endDateTime) ) 

You are comparing events from your query evExist which returns results for both owners with ones in evdatetimeMapper which is only for a single owner, as a result you are comparing 1 event of owner A in trigger context A (evWrapper) with evExist which can be either this same event or the event submitted by user B. This boolean passes because the two events have different owners and you never meant to compare them.

  • So will before insert prevent the issue for concurrency which I am facing right now? AddError works fine if there is a gap between save even of a millisecond but if together error does not even shows up and duplicates are saved Mar 15 '17 at 16:48
  • 2
    addError can roll back records in an after context, though.
    – sfdcfox
    Mar 15 '17 at 17:01
  • sfdcFox is correct, see updated answer above. Mar 16 '17 at 15:25

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.