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
AchtungAchtung 

Iterate the items on the List of List created - Apex Trigger Code

So I created a List of List in my Apex Trigger code to list out all service IDs and the Job IDs associated with them. The structure looks like this:
User-added image

The Service object contains the startDate and endDate fields. The Job object also has jobStart and jobEnd date fields.

What I intend to do is, if the dates of a Service record ID are updated, it will loop through all the jobs assigned to that service ID and check if there are dates that are not within the new date duration. This won't allow the user to update the Service record because jobs currently associated with it conflict with the new dates. 
Best Answer chosen by Achtung
Steven NsubugaSteven Nsubuga
Here is my version of such a trigger
Trigger checkValidServiceDates on Service__c (after  update) {    

    	
    Map<Id, List<job__c>> serviceJobs = new Map<Id, List<job__c>>();
	for(job__c serviceJob: [Select Id, Service__c, startDate__c, endDate__c From job__c WHERE Service__c IN :Trigger.newMap.keyset()]){
		if(!serviceJobs.containsKey(serviceJob.Service__c)) { 
			serviceJobs.put(serviceJob.Service__c, new List<job__c>());
		}
		serviceJobs.get(serviceJob.Service__c).add(serviceJob);
	}
	
    for (Service__c service : Trigger.new) {
        List<job__c> jobs = serviceJobs.get(service.Id);
		if (jobs!= null && jobs.size()> 0) {
			for (job__c job : jobs) {
				if (job.startDate__c < service.startDate__c || job.startDate__c > service.endDate__c) {
					service.addError('Existing jobs are out of range of the new service dates');
				}
				if (job.endDate__c < service.startDate__c || job.endDate__c > service.endDate__c) {
					service.addError('Existing jobs are out of range of the new service dates');
				}
			}
		}
    }
}

 

All Answers

Steven NsubugaSteven Nsubuga
Here is my version of such a trigger
Trigger checkValidServiceDates on Service__c (after  update) {    

    	
    Map<Id, List<job__c>> serviceJobs = new Map<Id, List<job__c>>();
	for(job__c serviceJob: [Select Id, Service__c, startDate__c, endDate__c From job__c WHERE Service__c IN :Trigger.newMap.keyset()]){
		if(!serviceJobs.containsKey(serviceJob.Service__c)) { 
			serviceJobs.put(serviceJob.Service__c, new List<job__c>());
		}
		serviceJobs.get(serviceJob.Service__c).add(serviceJob);
	}
	
    for (Service__c service : Trigger.new) {
        List<job__c> jobs = serviceJobs.get(service.Id);
		if (jobs!= null && jobs.size()> 0) {
			for (job__c job : jobs) {
				if (job.startDate__c < service.startDate__c || job.startDate__c > service.endDate__c) {
					service.addError('Existing jobs are out of range of the new service dates');
				}
				if (job.endDate__c < service.startDate__c || job.endDate__c > service.endDate__c) {
					service.addError('Existing jobs are out of range of the new service dates');
				}
			}
		}
    }
}

 
This was selected as the best answer
AchtungAchtung
Thanks Steven. That logic sounds right. I will try it on my developer console.
AchtungAchtung
Hi Steven,

Will ther be another way to avoid the For Loop inside the For Loop?

Thanks.
Steven NsubugaSteven Nsubuga
Hi Danilo, I do not see a way to avoid the nested for loop. 
There are no design principles that have been violated. This code will not hit any governor limits. 
The inner for loop is executed once per each item in the outer loop. 
AchtungAchtung
Hi Steven,

I'm revising my logic in such a way that only Agreements where either their start date or end date is changed will be stored in the Trigger.new set.

And also, to make the SOQL more efficient, I only want to search for jobs where their agreement Id is found the set above and their job start or end date violates the new agreement start or end date.

Can you help revise your code for this? Thanks.
 
Steven NsubugaSteven Nsubuga
Hi Danilo, here you go!
Trigger checkValidServiceDates on Service__c (after  update) {    

	Set<Id> serviceIds = new Set<Id>();
	for (Service__c service : Trigger.new) {
		if (Trigger.oldMap.get(service.Id).startDate__c != service.startDate__c || Trigger.oldMap.get(service.Id).endDate__c != service.endDate__c) {
			serviceIds.add(service.Id);
		}
    }
	
    Map<Id, List<job__c>> serviceJobs = new Map<Id, List<job__c>>();
	for(job__c serviceJob: [Select Id, Service__c, startDate__c, endDate__c From job__c WHERE Service__c IN :serviceIds AND startDate__c < service__r.startDate__c
	  OR endDate__c > service__r.endDate__c]){
		if(!serviceJobs.containsKey(serviceJob.Service__c)) { 
			serviceJobs.put(serviceJob.Service__c, new List<job__c>());
		}
		serviceJobs.get(serviceJob.Service__c).add(serviceJob);
	}
	
	for (Id serviceId : serviceJobs.keyset()) {
		Trigger.newMap.get(serviceId).addError('Existing jobs are out of range of the new service dates');
	} 
}