+ Start a Discussion
JJamesJJames 

Accessing related list data in trigger

I am a little unsure on how to go about doing this because my understanding of related lists on an object isn't completely there yet.  I want to create a trigger that accesses data in an opportunity.  The data I need to access is a related list of custom objects, the related list is called Quoted Products.  Would I access it something like:
trigger UpdateSplits on Opportunity (before update, before insert) 
{
    Set<id> eventIds = new Set<Id>();
    for (Opportunity opp : Trigger.new) {
        eventIds.add(opp.Quoted_Products__c);
    }
    Map<Id, Event__c> eventMap = new Map<id,Quoted_Products__c>([SELECT id, Name, 
                                                                       (SELECT Id, Name 
                                                                        FROM Products)
                                                       FROM Quoted_Products__c
                                                       WHERE id in :eventIds]);
//use data for other things 
}



Also, where are the related lists defined? I cannot find the related list in objects or labels.  This particular related list is a list of products but I would like to know where this list is named and setup.  Any help is greatly appreciated.
Best Answer chosen by JJames
James LoghryJames Loghry
Related lists are more of a terminology for displaying child relationships on page layouts.  Think of a related list more as the table of children on the page layout.  What you're looking for is how to access relationships via SOQL and triggers, and you're not too far off.

Before you go any further with the relationships though, I suggest you read up on the following documentation first: https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships.htm

Your trigger is going to look something like the following:
 
trigger UpdateSplits on Opportunity (before update, before insert) {
    
    if(Trigger.isAfter || Trigger.isUpdate){
        for(Quoted_Product__c qp : [Select Id,Name,(Select Id,Name From Products__r) From Quoted_Products__c Where Opportunity__c in :Trigger.newMap.keySet()]){

            //Logic on the quoted product goes here...

            for(Product__c childProduct : qp.Products__r){
                //Logic on the current childProduct goes here...
            }
        }
    }
}

I took a few guesses as to the api name of the opportunity lookup on the Quoted_Products__c object, and the API name of the Products child relationship on the Quoted_Products object as well.

Furthermore, Trigger.newMap.keySet() is only available on either after insert or before/after update, so this logic will not execute on before insert of the Opportunity record.

Hope that helps you get started at least.

 

All Answers

Carlos Campillo GallegoCarlos Campillo Gallego
Hi JJames!

Related Lists in every object show you all the records of other custom/standard objects that are referencing your current record. This relation is done using Lookup fields or Master Detail fields, so in your data model example, you would like to retrieve all the Quoted_Products__c that are referencing to a specific opportunity record.
You can see and edit the Label of the related list when you access to the lookup field. Maybe this pic will help you:Lookup Field Options
Whenever you create a custom lookup/master-detail field, you'll be asked to fill these fields but as you can see you can edit them later.

Hope this helps you :)

Kind regards,

Carlos.
James LoghryJames Loghry
Related lists are more of a terminology for displaying child relationships on page layouts.  Think of a related list more as the table of children on the page layout.  What you're looking for is how to access relationships via SOQL and triggers, and you're not too far off.

Before you go any further with the relationships though, I suggest you read up on the following documentation first: https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships.htm

Your trigger is going to look something like the following:
 
trigger UpdateSplits on Opportunity (before update, before insert) {
    
    if(Trigger.isAfter || Trigger.isUpdate){
        for(Quoted_Product__c qp : [Select Id,Name,(Select Id,Name From Products__r) From Quoted_Products__c Where Opportunity__c in :Trigger.newMap.keySet()]){

            //Logic on the quoted product goes here...

            for(Product__c childProduct : qp.Products__r){
                //Logic on the current childProduct goes here...
            }
        }
    }
}

I took a few guesses as to the api name of the opportunity lookup on the Quoted_Products__c object, and the API name of the Products child relationship on the Quoted_Products object as well.

Furthermore, Trigger.newMap.keySet() is only available on either after insert or before/after update, so this logic will not execute on before insert of the Opportunity record.

Hope that helps you get started at least.

 
This was selected as the best answer
JJamesJJames
Thank you, both of these clear things up and thanks for the link James, that is exactly what I need to review.  So in this case the related list is just a label for a group of objects and the list name actually has no value to what I am trying to accomplish, I need to query the object that is in the list.  
Question - what if I have 2 lists in an opportunity with the same object type , say commission based product sales and another list non commission sales, is there a way to only access the products from one list ? Or would I need some type of flag on the product object and filter each object by checking the flag?  
James - the code you provided references Quoted_Product__c which is not an Object, just the label for the related list (which doesn't have an api call name as I see)  So I wouldn't be able to use the label name in the code, correct?
Carlos Campillo GallegoCarlos Campillo Gallego
If you have two lists is because you have two different lookup fields (even if they reference the same object) so you would be able to access one or another easily because of ther different api names.

Kind regards :)

Carlos.
James LoghryJames Loghry
Yeah, I mentioned in my post that I was simply guessing at the API names for your code.  I grabbed Quoted_Product from your original example.  You'll need to find the exact API name by either using the Schema Builder, or by going to Setup->Create->Object and looking for the API name of the object (or by going to the lookup field and looking for the child relationship API name).

If you have two related lists / relationships, it's no big deal.  It means either an additional relationship in your SOQL query or a new SOQL query all together, depending on your logic / data model.
JJamesJJames
Okay thanks.  This is a big help, and i reviewed the relationship queries documentation.  Last thing that is unclear to me is the child relationship API name.  I only see the child relationship name which is QuoteItems, can i assume that the api name is QuoteItems__c or is there a field that should be apparent there?  In the object lookup shown below I am trying to access the quoteitems related list items from the opportunity.  
User-added image
and when trying to use either QuoteItems or QuoteItems__c in the following code it returns the error message afterwards:
trigger UpdateSplits on Opportunity (before update, before insert) {
    List<QuoteItem> qItem = new List<QuoteItem>();
    if(Trigger.isAfter || Trigger.isUpdate){
        for(QuoteItem__c qi : [Select Id,Name,REVVY__Price__c From QuoteItems__c Where Opportunity__c in :Trigger.newMap.keySet()]){
            qItem.add(qi);
            //Logic on the quoted product goes here...

            for(Product__c childProduct : qp.Products__r){
                //Logic on the current childProduct goes here...
            }
        }
    }
}

Error: Compile Error: sObject type 'QuoteItems__c' is not supported. If you are attempting to use a custom object, be sure to append the '__c' after the entity name. Please reference your WSDL or the describe call for the appropriate names. at line 4 column 31
James LoghryJames Loghry
Not entirely intuitive :) but child relationship names are suffixed with __r instead of __c.

Also, make sure you get the name of the child relationship instead of the label.  Hope that helps.
JJamesJJames
Is there any reason why this should not be working?  :
trigger UpdateSplits on Opportunity(before update, before insert) 
{

    for( REVVY__Opportunity__c acc : [ Select Id, (Select Id,Name  FROM QuoteItems__r) FROM Opportunity where Id IN: trigger.new ])
    {

    }
}

Error: Compile Error: Didn't understand relationship 'QuoteItems__r' in FROM part of query call. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names. at line 10 column 29
JJamesJJames
oops, i meant:
 
trigger UpdateSplits on Opportunity(before update, before insert) 
{

    for( Opportunity acc : [ Select Id, (Select Id,Name  FROM QuoteItems__r) FROM Opportunity where Id IN: trigger.new ])
    {

    }
}

 
JJamesJJames
Figured it out, didnt have the appropriate API name, thanks for all your guys help