0

I have the following data model:

enter image description here

My purpose is to get all the needed data from the server-side on the client side. And I need to know: all the assessments, for each assessment I need to know questions which are related to it, for each question I need to know all the related answers. And for both questions and assessments I may need a few fields (for example, for a question in addition to a list of answers I need a question text and question directions).

I am using guides provided in the answer to retrieve the data using SOQL.

Here is what my request looks so far:

List<zced__Assessment__c> assessmentAndQuestions = [
            SELECT Id, (SELECT Id FROM zced__Assessment_Questions__r)
            FROM zced__Assessment__c
            WHERE zced__Interaction__c = :interactionId
        ];

        Set<String> questions = new Set<String>();
        Map<String, List<String>> assessmentToQuestions = new Map<String, List<String>>();
        for(zced__Assessment__c assessment: assessmentAndQuestions) {
            assessmentToQuestions.put(assessment.Id, new List<String>());
            for(zced__Assessment_Question__c question: assessment.zced__Assessment_Questions__r) {
                assessmentToQuestions.get(assessment.Id).add(question.Id);
                questions.add(question.Id);
            }
        }

        Map<Id, zced__Assessment_Question__c> questionToAnswers = new Map<Id, zced__Assessment_Question__c> ([
            SELECT zced__Question_text__c, zced__Question_Instruction__c,
            (
                SELECT zced__Answer_Text__c, zced__Is_Correct__c, zced__Answer_Points__c
                FROM zced__Assessment_Answers__r
            )
            FROM zced__Assessment_Question__c
            WHERE Id IN :questions
        ]);

As you can see I gathered all the needed data and now it comes to assembling the data into a data structure and sending it to the client-side.

So, what I was able to come up with is the following:

I would have a List<List<List<List<SObject>>>> res;. Where res[q][w][e+d] would mean the data about the e-th answer which is in w-th question in q-th assessment. While the objects res[q][w][e], res[q][w][e+1], ..., res[q][w][e+d] would hold a w-th question`s in q-th assessment fields which I will need on the client side.

I am feeling that my solution is very clumsy. Are there different approaches to solving such kinds of problems?

Here is my code after the answer was provided:

@AuraEnabled
    public static QuizDataNode retrieveQuizInfo(String interactionId) {
        QuizDataNode res = new QuizDataNode(null);

        List<zced__Assessment__c> assessmentAndQuestions = [
            SELECT Id, (SELECT Id FROM zced__Assessment_Questions__r)
            FROM zced__Assessment__c
            WHERE zced__Interaction__c = :interactionId
        ];

        Set<String> questions = new Set<String>();
        Map<String, List<String>> assessmentToQuestions = new Map<String, List<String>>();
        for(zced__Assessment__c assessment: assessmentAndQuestions) {
            assessmentToQuestions.put(assessment.Id, new List<String>());
            for(zced__Assessment_Question__c question: assessment.zced__Assessment_Questions__r) {
                assessmentToQuestions.get(assessment.Id).add(question.Id);
                questions.add(question.Id);
            }
        }

        Map<Id, zced__Assessment_Question__c> questionToAnswers = new Map<Id, zced__Assessment_Question__c> ([
            SELECT zced__Question_text__c, zced__Question_Instruction__c,
            (
                SELECT zced__Answer_Text__c, zced__Is_Correct__c, zced__Answer_Points__c
                FROM zced__Assessment_Answers__r
            )
            FROM zced__Assessment_Question__c
            WHERE Id IN :questions
        ]);

        for(zced__Assessment__c e: [
            SELECT Id
            FROM zced__Assessment__c
            WHERE zced__Interaction__c = :interactionId
        ]) {
            QuizDataNode qdn = new QuizDataNode(new zced__Assessment__c(Id = e.Id));
            for(String f: assessmentToQuestions.get(e.Id)) {
                qdn.addChild(new QuizDataNode(questionToAnswers.get(f)));
            }
            res.addChild(qdn);
        }

        return res;
    }


public class QuizDataNode {
    @AuraEnabled
    public SObject sob {get; set;}

    @AuraEnabled
    public QuizDataNode parent {get; private set;}
    @AuraEnabled
    public List<QuizDataNode> children {get; private set;}

    public QuizDataNode(SObject sob) {
        this.sob = sob;
        children = new List<QuizDataNode>();
    }

    public void addChild(QuizDataNode child) {
        children.add(child);
        child.parent = this;
    }
}

When I call the method on the client-side it returns with a state of an ERROR. And here is what it tells me:

message:

"Communication error, please retry or reload the page"

stack:

Error: Communication error, please retry or reload the page at U.z.oh (https://zeddev-dev-ed.lightning.force.com/auraFW/javascript/M8mitrSnSoFe6Y855DnNgg/aura_prod.js:587:435) at Object.onXHRReceived (https://zeddev-dev-ed.lightning.force.com/libraries/instrumentation/idleDetector/idleDetector.js:2:265) at Object.TA.Ak (https://zeddev-dev-ed.lightning.force.com/auraFW/javascript/M8mitrSnSoFe6Y855DnNgg/aura_prod.js:240:255) at UG.xp (https://zeddev-dev-ed.lightning.force.com/auraFW/javascript/M8mitrSnSoFe6Y855DnNgg/aura_prod.js:835:421) at Object.TA.Ak (https://zeddev-dev-ed.lightning.force.com/auraFW/javascript/M8mitrSnSoFe6Y855DnNgg/aura_prod.js:240:255) at TA.start (https://zeddev-dev-ed.lightning.force.com/auraFW/javascript/M8mitrSnSoFe6Y855DnNgg/aura_prod.js:239:313) at XMLHttpRequest.e (https://zeddev-dev-ed.lightning.force.com/auraFW/javascript/M8mitrSnSoFe6Y855DnNgg/aura_prod.js:577:103)

What am I doing wrong here?

2

Better to think of this as a tree where each parent has multiple children. You can create a wrapper class or multiple wrapper classes to model that relationship where the wrapper also holds a reference to the specific SObject.

I’m using my phone so too painful to add example code but hope this helps a bit.

PS

The code would look something like this:

public class Node {

    public SObject sob {get; set;}

    public Node parent {get; private set;}
    public Node[] children {get; private set;}

    public Node(SObject sob) {
        this.sob = sob;
        children = new Node[] {};
    }

    public void addChild(Node child) {
        children.add(child);
        child.parent = this;
    }
}

and to build the tree:

Node root = new Node(null);
for (...) {
    Node assessment = new Node(assessmentSob);
    root.addhild(assessment);
    for (...) {
        Node question = new Node(questionSob);
        assessment.addChild(question);
        for (...) {
            Node answer = new Node(answerSob);
            question.addChild(answer);
        }
    }
}

The sob can be cast to the appropriate type.

6
  • Yes, I am not very clear what you are talking about here. So, it would be nice to see maybe a schema drawn (of if it is easier some code provided). – iloveseven Jul 15 '18 at 15:57
  • 1
    @iloveseven what Keith means is that you can create a class which wraps a certain list of another class which wraps another. Kind of like the Matryoshka dolls. It's not the cleanest of codes, but Apex can't do much better imo. – Javier García Manzano Jul 16 '18 at 8:58
  • Should I return root to the client-side part? Or are there a better way to return the result? – iloveseven Jul 16 '18 at 13:14
  • @iloveseven I'd return the root but alternatively you could add a getter that returns the root's list and return that. – Keith C Jul 16 '18 at 13:40
  • Could you, please check the question. I updated it to ask about some implementation issues. – iloveseven Jul 16 '18 at 13:45

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.