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
duke1duke1 

Writing first Trigger, problem updating field

I'm trying to implement my first trigger.  I have a lookup relationship between MasterLookup and ChildDetail objects.  Here is the trigger:

 

trigger updateOnQtyCountTotal on Master_Lookup__c (before insert, before update) {
    // Use parent-child relationship to find all quantities for each Master_Lookup
    String queryString = 'SELECT Id, Total_Quantity__c, (SELECT Quantity__c from Child_Detail__r) from Master_Lookup__c';
    Master_Lookup__c[] myMasterLookup = Database.query(queryString);
    for (Master_Lookup__c masterLookupRecord : myMasterLookup){
        sObject[] childRecordsFromMaster = masterLookupRecord.getSObjects('Child_Detail__r');
        Decimal runningTotal = 0;
        // Prevent a null relationship from being accessed
        if (childRecordsFromMaster != null) {
            for (sObject childRecord : childRecordsFromMaster){
                runningTotal += (Decimal)childRecord.get('Quantity__c');
            }
        }
        masterLookupRecord.Total_Quantity__c = runningTotal;
    }
}

 

The last line is not updating the Total_Quantity__c field when I view the MasterLookup object after making a change to the object.  It is clearly running the code in the trigger when I view the log, but the field is always blank.  This must be an obvious error, but I can't find it and searching the documentation has not helped.  Thanks.

Best Answer chosen by Admin (Salesforce Developers) 
Jeremy.NottinghJeremy.Nottingh

First, forgive me if I'm asking a dumb question, but why don't you just set up a rollup summary formula field on Master_Lookup__c? That would do the calculation you have here, right? And it wouldn't require any code at all.

 

However, if you really need a Trigger, make sure you're making use of Trigger.new. Your code right now will run on all Master_Lookup__c objects in your organization every time one of them is edited. Really, it seems to me like your Trigger should run off of Child_Detail__c rather than Master_Lookup__c, since you'll only need it if the child is updated, not necessarily the master.

 

Anyway, to get to the bottom of the problem you mention below, try putting some system.debug() statements in there, so you can see what the Child_Detail__r list really looks like, and watch runningTotal get added up. If you can figure out where the ball gets dropped, I'll be happy to help further.

 

Jeremy

All Answers

duke1duke1

I solved the problem by invoking the trigger from the child detail and updating the master lookup inside that trigger.

Jeremy.NottinghJeremy.Nottingh

First, forgive me if I'm asking a dumb question, but why don't you just set up a rollup summary formula field on Master_Lookup__c? That would do the calculation you have here, right? And it wouldn't require any code at all.

 

However, if you really need a Trigger, make sure you're making use of Trigger.new. Your code right now will run on all Master_Lookup__c objects in your organization every time one of them is edited. Really, it seems to me like your Trigger should run off of Child_Detail__c rather than Master_Lookup__c, since you'll only need it if the child is updated, not necessarily the master.

 

Anyway, to get to the bottom of the problem you mention below, try putting some system.debug() statements in there, so you can see what the Child_Detail__r list really looks like, and watch runningTotal get added up. If you can figure out where the ball gets dropped, I'll be happy to help further.

 

Jeremy

This was selected as the best answer
Going South.ax738Going South.ax738

Also dont foget the headaches of writing test methods ;)

duke1duke1

I implemented Jeremy's idea of invoking the trigger on the Child_Detail instead of the Master_Lookup and it worked fine.  See Trigger 1 below, which works fine.

 

I then tried to implement his idea of using Trigger.new so that I am only working on those records that had changed.  See Trigger 2 below.  I first created a set of Master_Lookup's to avoid duplicates and then created a list from the set so I should have the same construction going into the "main for loop" as I did in the Trigger 1, except this time I'm working only with a list of changed records.  However, with Trigger 2, I get a null pointer exception on the line:

 

sObject[] childRecordsFromMaster = masterLookupRecord.getSObjects('Child_Detail__r');

I'm not clear why this line works in Trigger 1 and not Trigger 2.  Any help would be greatly appreciated.

 

Trigger 1:

trigger updateOnQtyCountTotal on Child_Detail__c (after insert, after update) {
    // Use parent-child relationship to find all quantities for each Master_Lookup
    String queryString = 'SELECT Id, Total_Quantity__c, Total_Price__c, ' +
                         'Total_Count__c, (SELECT Quantity__c, Total_Price__c ' +
                         'from Child_Detail__r) from Master_Lookup__c';
    Master_Lookup__c[] myMasterLookup = Database.query(queryString);

    // Main for loop
    for (Master_Lookup__c masterLookupRecord : myMasterLookup){
        sObject[] childRecordsFromMaster = masterLookupRecord.getSObjects('Child_Detail__r');
        Decimal runningQuantityTotal = 0;
        Decimal runningPriceTotal = 0;
        Decimal runningItemsTotal = 0;
        // Prevent a null relationship from being accessed
        if (childRecordsFromMaster != null) {
            for (sObject childRecord : childRecordsFromMaster){
                runningQuantityTotal += (Decimal)childRecord.get('Quantity__c');
                runningPriceTotal += (Decimal)childRecord.get('Total_Price__c');
                runningItemsTotal++;
            }
        }
        masterLookupRecord.Total_Quantity__c = runningQuantityTotal;
        masterLookupRecord.Total_Price__c = runningPriceTotal;
        masterLookupRecord.Total_Count__c = runningItemsTotal;
    }
    upsert myMasterLookup;
}

 

Trigger 2

trigger updateOnQtyCountTotal on Child_Detail__c (after insert, after update) {
    Child_Detail__c[] myChildDetail = Trigger.new;
    // Form a set of affected MasterLookupRecords to avoid duplicates
    Set<Master_Lookup__c> myMasterLookupSet = new Set<Master_Lookup__c>();
    for (Child_Detail__c myChildDetailRecord : myChildDetail){
        myMasterLookupSet.add((Master_Lookup__c)myChildDetailRecord.getSObject('Master_Lookup__r'));
    }
    Master_Lookup__c[] myMasterLookup = new List<Master_Lookup__c>();
    myMasterLookup.addAll(myMasterLookupSet);

    // Main for loop
    for (Master_Lookup__c masterLookupRecord : myMasterLookup) {
        sObject[] childRecordsFromMaster = masterLookupRecord.getSObjects('Child_Detail__r');
        Decimal runningQuantityTotal = 0;
        Decimal runningPriceTotal = 0;
        Decimal runningItemsTotal = 0;
        // Prevent a null relationship from being accessed
        if (childRecordsFromMaster != null) {
            for (sObject childRecord : childRecordsFromMaster){
                runningQuantityTotal += (Decimal)childRecord.get('Quantity__c');
                runningPriceTotal += (Decimal)childRecord.get('Total_Price__c');
                runningItemsTotal++;
            }
        }
        masterLookupRecord.Total_Quantity__c = runningQuantityTotal;
        masterLookupRecord.Total_Price__c = runningPriceTotal;
        masterLookupRecord.Total_Count__c = runningItemsTotal;
    }
    upsert myMasterLookup;
}