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
mrizmriz 

SOQL: how to have 1-1 mapping of objects sharing 1-M relationship

I have two custom objects Project__c & task__c (custom task, so that same task can be allocated to multiple people). one project can have multiple tasks, but task is uniquely associated with project.
I can't use lookup field in task for Project due to my design constraint. I am rather having a field project_id__c holding ID of project in task.

Apex Code:
public class TestClass1{
	public List<Id> tasks{get;set;}
	public Map<Id,String> taskMap{get;set;} //  to hold task id and project name
	
	public TestClass1(){
		try{
			tasks = [SELECT id,name,project_id__c FROM Task__c];
			projectNames();
		}catch(Exception e){
			System.debug(e);
		}
	}
	
	public void projectNames(){
		List<Id> projectIds = new List<Id>;
		for(Task__c t:tasks)
			projectIds.add(t.project_id__c);
			
		System.debug('Size of tasks: '+tasks.size());
		
		List<Project__c> projects = [SELECT name FROM Project__c WHERE id IN:projectIds]
		System.debug('Size of projects: '+projects.size());
		
		/*
		this section fails when, say 3 out of 5 tasks are part of one project
		for(Integer i=0;i<tasks.size();i++)
			taskMap.put(t[i].id,projects[i].name);
		*/
	}
}
I am facing problem in handling bulkified query.

one quickFix is to query project object inside for loop, but that is extrememly poor approach in SFDC.

Whats solution for this?
 
Best Answer chosen by mriz
Abhishek BansalAbhishek Bansal
Hi Mritizi,

I have updated your code to fulfill your requirement.
Please find the updated code below :
public class TestClass1{
	public List<Id> tasks{get;set;}
	public Map<Id,String> taskMap{get;set;} //  to hold task id and project name
	
	public TestClass1(){
		try{
			tasks = [SELECT id,name,project_id__c FROM Task__c];
			projectNames();
		}catch(Exception e){
			System.debug(e);
		}
	}
	
	public void projectNames(){
		List<Id> projectIds = new List<Id>;
		for(Task__c t:tasks)
			projectIds.add(t.project_id__c);
			
		System.debug('Size of tasks: '+tasks.size());
		
		//Code update by Abhishek : Start/End
		Map<Id,Project__c> projects = new Map<Id,Project__c>([SELECT name FROM Project__c WHERE id IN:projectIds]);
		System.debug('Size of projects: '+projects.size());
		
		/*
		this section fails when, say 3 out of 5 tasks are part of one project
		for(Integer i=0;i<tasks.size();i++)
			taskMap.put(t[i].id,projects[i].name);
		*/
		
		//Code added by Abhishek : Start
		for(Task__c tsk : tasks){
			if(projects.containsKey(tsk.project_id__c)){
				taskMap.put(projects.get(tsk.project_id__c).id,projects.get(tsk.project_id__c).Name);
			}
		}
		//Code added by Abhishek : End
	}
}

I have added the comments in code where i have performed updates.

Please use the above code and let me know if you have any issue with this.

Thanks,
Abhishek Bansal

All Answers

Abhishek BansalAbhishek Bansal
Hi Mritizi,

I have updated your code to fulfill your requirement.
Please find the updated code below :
public class TestClass1{
	public List<Id> tasks{get;set;}
	public Map<Id,String> taskMap{get;set;} //  to hold task id and project name
	
	public TestClass1(){
		try{
			tasks = [SELECT id,name,project_id__c FROM Task__c];
			projectNames();
		}catch(Exception e){
			System.debug(e);
		}
	}
	
	public void projectNames(){
		List<Id> projectIds = new List<Id>;
		for(Task__c t:tasks)
			projectIds.add(t.project_id__c);
			
		System.debug('Size of tasks: '+tasks.size());
		
		//Code update by Abhishek : Start/End
		Map<Id,Project__c> projects = new Map<Id,Project__c>([SELECT name FROM Project__c WHERE id IN:projectIds]);
		System.debug('Size of projects: '+projects.size());
		
		/*
		this section fails when, say 3 out of 5 tasks are part of one project
		for(Integer i=0;i<tasks.size();i++)
			taskMap.put(t[i].id,projects[i].name);
		*/
		
		//Code added by Abhishek : Start
		for(Task__c tsk : tasks){
			if(projects.containsKey(tsk.project_id__c)){
				taskMap.put(projects.get(tsk.project_id__c).id,projects.get(tsk.project_id__c).Name);
			}
		}
		//Code added by Abhishek : End
	}
}

I have added the comments in code where i have performed updates.

Please use the above code and let me know if you have any issue with this.

Thanks,
Abhishek Bansal

This was selected as the best answer
Mahesh DMahesh D
Hi Mritizi,

In addition to Abhishek's code, I modified few things.

Please check the below code:
 
public class TestClass1 {
	public List<Id> tasks{get;set;}
	public Map<Id,String> taskMap{get;set;} //  to hold task id and project name
	
	public TestClass1() {
		try {
			tasks = [SELECT id,name,project_id__c FROM Task__c];
			projectNames();
		} catch(Exception e) {
			System.debug(e);
		}
	}
	
	public void projectNames() {
		Set<Id> projectIdSet = new Set<Id>;
		for(Task__c t:tasks) {
			if(t.project_id__c != null)
				projectIdSet.add(t.project_id__c);
		}
			
		System.debug('Size of tasks: '+tasks.size());
		
		if(!projectIdSet.isEmpty()) {
			Map<Id, Project__c> projectMap = new Map<Id, Project__c>([SELECT name FROM Project__c WHERE id IN:projectIdSet]);
			System.debug('Size of projects: '+projectMap.size());
			
			for(Task__c tsk : tasks){
				if(tsk.project_id__c != null && projectMap.containsKey(tsk.project_id__c)){
					taskMap.put(projectMap.get(tsk.project_id__c).id, projectMap.get(tsk.project_id__c).Name);
				}
			}
		}
	}
}

Here I followed the best practices, null checks and few naming conventions.

Please let me know if this helps you.

Regards,
Mahesh