0

I have a requirement to insert a 2 level nested JSON structure in Apex. I have 2 objects created, say, objA__c and objB__c. objB__C has Master Detail relationship to objA__c.

objA and objB items can repeat any number of times and we should have one record of respective type created for each repetition.

I have written the below apex rest class with to insert the nested structure in a single DML, but i am facing a problem as to how can i generate the reference to establish the relationship. Is there a way in Apex to generate a unique sequence while just instantiating an instance of the onject i.e before inserting the record ?

I know the auto number field and the Id field values can be fetched only after insert.

Note: Its working fine if i pass the value of the external Id in the JSON and use it to reference, but thats not what i want in real time as it wont be present in the JSON. Also using Custom setting to store a numeric value and using that in reference field and then incrementing it after using it everytime is working , but thats not what i want. Any help would be appreciated. Thanks.

Inbound JSON Structure:

{   
    "objA_Details": [
        {
            "AName": "objA_Record_1",
            "AType": "abcType",
            "objB_Details": [
                {
                    "BName": "objB_Record_1",
                    "BType": "xyzType",
                },
                {
                    "BName": "objB_Record_2",
                    "Bype": "abcType",
                }
            ]
        },
        {
            "AName": "objA_Record_2",
            "AType": "abcType",
            "objB_Details": [
                {
                    "BName": "objB_Record_1",
                    "BType": "abcType",
                }
            ]
        },
        {
            "AName": "objA_Record_3",
            "AType": "abcType",
            "objB_Details": [
                {
                    "BName": "objB_Record_1",
                    "BType": "xyzType",
                }
            ]
        }
    ]
}

Apex Code:

@RestResource(urlmapping='/abcInsert')
global class abcInsert {
    public static string Json_Request;
    @httpPost
    global static void doCreate(){
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;
        Blob Json_Req=req.requestBody;
        Json_Request=Json_Req.toString();
        try{
            objA_Details JRequest = (objA_Details) System.JSON.deserialize(Json_Request,objA_Details.class);
            List<objA__c> insertA = new List<objA__c>();
            List<objB__c> insertB = new List<objB__c>();
            for(objA_Details aDetails : JRequest.objA_Details){
                objA__c newA = new objA__c();
                objA__c aReference = new objA__c(Extr_Id__c=????);
                newA.AName__c=aDetails.AName;
                newA.AType__c=aDetails.AType;
                newA.Extr_Id__c=????;
                insertA.add(newA);
                for(objB_Details bDetails : aDetails.objB_Details){
                    objB__c newB= new objB__c();
                    newB.BName__c=bDetails.BName;
                    newB.BType__c=bDetails.BType;
                    newB.Extr_Id__c=newB.Auto_Num_Ref__c;
                    newB.objA__r = aReference;
                    insertB.add(newB);
                }
            }
            List<Database.upsertResult> srList = Database.upsert(insertA, objA__c.Extr_Id__c.getDescribe().getSObjectField());
            List<Database.upsertResult> srList1 = Database.upsert(insertB, objB__c.Extr_Id__c.getDescribe().getSObjectField());
        }
                catch(Exception e){
                    System.debug(e.getMessage()+ '\nLineNumber:'+ e.getLineNumber());
        }

        }
    global class objA_Details{
            public String AName,AType;
            public List<objB_Details> objB_Details;
    }
    global class objB_Details{
        public String BName,BType;
    }
}

1 Answer 1

0

There are a couple of considerations here,

Upsert is not possible without you needing an externalId.

Generating externalID like Auto Number yourself is not something I would recommend. This is because you will end up using SOQL to query for existing ExternalId in the table. Querying will get expensive as your table grows.

One way will be if you find attributes that, upon concatenation, can be unique. For example, can a combo of name + Type is unique? If you can find anything like that, then that can be externalId.

Doing an Upsert in a single DML is not possible for different Sobjects.

So looking at both the consideration, I would question what the need to do an upsert in a single operation. Instead using a separate DML should be good enough.

You can rely on the list indexes to make sure parent and child have the correct relationship as in the external system.

for(integer i=0 ; i <JRequest.objA_Details.size() : ; i ++){
            objA_Details aDetails = JRequest.objA_Details[i];
            objA__c newA = new objA__c();
            newA.AName__c=aDetails.AName;
            newA.AType__c=aDetails.AType;
            insertA.add(newA);
            for(objB_Details bDetails : aDetails.objB_Details){
                objB__c newB= new objB__c();
                newB.BName__c=bDetails.BName;
                newB.BType__c=bDetails.BType;
                newB.objA__c = insertA[i].Id;
                insertB.add(newB);
            }
        }
     ../ At this point, I recommend doing an upsert with an externalId, like may be the concatenation of Name and Type. 
2
  • I am doing separate DML upserts for objA and objB. The need to do that in the same method is to maintain the relationship intact between the objects.
    – UserSF_321
    Commented Nov 13, 2022 at 6:31
  • I enhanced a bit, check the edits! Commented Nov 13, 2022 at 13:09

You must log in to answer this question.

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