2

I need to construct one object that will return Forms->Section->Question The objects are Master-Child relationships in the above order.

Please let me know how I can construct this object. Appreciate your help.

@RestResource(urlMapping='/FormSectionQuestions/*')
global with sharing class FormSectionQuestions{

    @HttpGet
    global static List<Form__c> doGet() {

        List<Form__c> objects = [SELECT Active__c, IsDeleted, Name, FormId__c, LastModifiedDate,Title__c, Version__c ,(SELECT ParentSection__c,Sort_Order__c, Title__c,name FROM Sections__r) FROM Form__c];

        for(Form__c form : objects){
            for(Section__c secRelation:form.Sections__r ){
                List<Question__c> questions = 
            [select  IsDeleted, Options__c, PostText__c, PreText__c, Name, Required__c,SectionId__c, Sort_Order__c, Text__c, Type__c, Validation__c FROM Question__c where SectionId__c=:secRelation.Id];
                secRelation.put('questionsHere',questions);//ERRORS here
                }
        }

        return objects;
    } 
}
6
  • The error is System.SObjectException: Invalid field QuestionsHere for Section__c .I understand the error because there is no field like that. But Otherwise, how can I construct an object out of multilevel parent-child relationships Commented Feb 10, 2017 at 20:45
  • Well you are trying to put your List<Question__c> onto a field questionsHere on Section__c records. So if that field doesn't exist, not sure what you are expecting Commented Feb 10, 2017 at 20:56
  • Nothing related to your question... But putting SOQL in for loops, not to mention nested for loops, is usually bad practice. Commented Feb 10, 2017 at 20:57
  • Hi Jesse thanks for your suggestion. My Objective is to return one Object that will have ParentDetails->ChildDetails->GrandChildDetails all in on object .. so that the rendered Json is hierarchical starting from Parent and ending with corresponding grand child Commented Feb 10, 2017 at 20:58
  • Please check my answer Commented Feb 11, 2017 at 1:41

1 Answer 1

3

I have tried to put your use case with Account --> Opportunities --> Tasks so that I can test the entire code logic.

Since your requirement is to return the entire result as a list of Single object so, I have created a wrapper class based on those objects.

1) OpportunityWrapper: which contains Opportunity and List<Task>

2) WrapperAccountClass: which contains Account and List<OpportunityWrapper>

And finally, I am returning List<WrapperAccountClass>.

I have maintained the bulkification of code and not to perform SOQL query in for loop.

@RestResource(urlMapping='/AccountWrapTesting/*')
global with sharing class AccountWrapTesting
{
    @HttpGet
    global static List<WrapperAccountClass> doGet() 
    {
        List<WrapperAccountClass> lstWrapperAccountClass = new List<WrapperAccountClass>();
        List<OpportunityWrapper> lstAllOpportunityWraps = new List<OpportunityWrapper>();
        //retrieve the account details with opportunities
        List<Account> lstAccount = [SELECT Account.Id, Name, (SELECT Id, Name FROM Opportunities) 
                                    FROM Account 
                                    WHERE Id IN ('001q000000UDpxF','001q000000U1RW5')];


        Set<Id> allOpptyIds = new Set<Id>(); //store Opportunity Ids.
        for(Account acct:lstAccount)
        {
            WrapperAccountClass acctWrap = new WrapperAccountClass();
            acctWrap.accountId = acct.Id;            
            List<OpportunityWrapper> lstOpptyWrap = new List<OpportunityWrapper>();

            //loop through the opportunities and put into wrapper.
            for(Opportunity opty:acct.Opportunities)
            {
                OpportunityWrapper objOptWrap = new OpportunityWrapper();
                objOptWrap.opptyId = opty.Id;
                lstOpptyWrap.add(objOptWrap);
                allOpptyIds.add(opty.Id);
                lstAllOpportunityWraps.add(objOptWrap);
            }
            acctWrap.lstOpportunityWrapper =lstOpptyWrap;

            lstWrapperAccountClass.add(acctWrap);
        }

        //now we got opportunities, lets capture list of task based on opportunity ids.
        getTask(allOpptyIds,lstWrapperAccountClass);        
        return lstWrapperAccountClass;
    }

    global static void getTask(Set<Id> allOpptyIds, List<OpportunityWrapper> lstAllOpportunityWraps)
    {
        //retrieve task based on opportunities
        List<Task> lstActivity = [SELECT Id, subject, whatId FROM Task WHERE WhatId=:allOpptyIds];

        //now loop through the wrapper class and put the task list related to opportunity
        for(OpportunityWrapper wrap:lstAllOpportunityWraps) {
            List<Task> lstInnerTask = new List<Task>();         
            for(Task taskOj:lstActivity) {
                if(wrap.opptyId == taskOj.whatId)  {
                    lstInnerTask.add(taskOj);
                    wrap.lstTask = lstInnerTask;
                }
            }
        }       
    }

    global class WrapperAccountClass
    {
        global Id accountId {get;set;}
        global List<OpportunityWrapper> lstOpportunityWrapper {get;set;}
    }

    global class OpportunityWrapper
    {
        global Id opptyId {get;set;}
        global List<Task> lstTask {get;set;}
    }  

}

End Result

Rest testing with relationships

Hope it helps!

1
  • To optimize this and avoid the nested for loops in getTask, a map of OppoIdToAccountWrapper will be helpful
    – cropredy
    Commented Feb 11, 2017 at 20:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .