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
Aaron HillAaron Hill 

Trigger to Update Fields with data from a parent object

So I was searching the community for something similar to this but I was hitting a wall because admittedly I don't know the nature of the relationship. I've set it up so that our standard account object has a field called Related Company. This is a vlookup field that can select a custom object called "Company" (there's another trigger in place that matches Accounts with Companies based on a name match). We've built a database of "Companies" that has 3 fields: LinkedIn, Industry, and Size. We want to pull this data from the related company and in to the matching account, to update the fields with the correct info from the Company object. 

Below is the code I have so far:
 
trigger updateAccountInfo on Account (before update) {
    
    
    for(Account acc : Trigger.new) {
        if(acc.Related_Company__c != null) {
            String comp = acc.Related_Company__c;
            accountInfo = [Select Industry__c, LinkedIn__c, Size__c 
                           from Related_Company__r 
                           where acc.Related_Company__c = :comp.Id];
            
            
        }
    }
}



I use the relationship __r connector but I still get the following message:

"sObject type 'Related_Company__r' 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."

So here's my question that I can't seem to figure out, Since this trigger is acting on account, which looks up to Company, does that mean that the SOQL query should utilize a Child to Parent relationship? And if so, isn't that what I'm doing? I apologize if this is all really basic I'm somewhat of a newbie. 

TL;DR How can I correct my syntax so that I can access a related object and update the fields within the Account Standard Object?

​Thanks!
Best Answer chosen by Aaron Hill
James LoghryJames Loghry
You have the generally right idea.  __r is used to select a related field based on the object you're querying.  However, the object you're querying will have the __c suffix if it's a custom object or no suffix at all if it's a standard object.

Typically, you could use  a query like:
 
List<Account> account = [Select Related_Company__r.LinkedIn__c From Account Where Id in :Trigger.new.keySet()];

However, issuing queries in a loop is a bad practice, as you'll hit governor limits easily when dealing with Account records.

I took your example above and "bulkified" it by using sets to query for the related companies in one query, then iterating through the results to modify the account fields.
trigger updateAccountInfo on Account (before update) {
    
    
    Set<Id> companyIdSet = new Set<Id>();
    for(Account acc : Trigger.new) {
        companyIdSet.add(acc.Related_Company__c);
    }

    Map<Id,Company__c> companiesMap = new Map<Id,Company__c>([Select Industry__c,LinkedIn__c,Size__c From Company__c Where Id in :companyIdSet]);

    for(Account a : Trigger.new){
       Company__c relatedCompany = companiesMap.get(a.Related_Company__c);

       //Set the account fields to related company fields here
    }
}

 

All Answers

Rajiv Penagonda 12Rajiv Penagonda 12
Aaron Hill, your query could be on Account instead of on Related Company as follows:
 
List<Account> lAccounts = Trigger.New;

Related_Company__c [] lCompanies = [SELECT Related_Company__r.Industry__c, Related_Company__r.LinkedIn__c, Related_Company__r.Size__c FROM Account WHERE id IN:lAccounts];

On the same note, I think you could tweak your design a little by having formula fields for Industry, LinkedIn and Size instead of updating text fields from within the trigger. Hope this helps.
Mahesh DMahesh D
Hi Aaron,

Please find the below code:
 
trigger UpdateAccountInfo on Account (before insert, before update) {
    Set<Id> compIdSet = new Set<Id>();
	for(Account acc : Trigger.new) {
        if(acc.Related_Company__c != null && (Teigger.isInsert || acc.Related_Company__c != Trigger.oldMap.get(acc.Id).Related_Company__c)) {
			compIdSet.add(acc.Related_Company__c);
		}
	}
	if(!compIdSet.isEmpty() {
		Map<Id, Company__c> compMap = new Map<Id, Company__c>([Select Id, Name, Industry__c, LinkedIn__c, Size__c from Company where Id IN: compIdSet]);
		for(Account acc : Trigger.new) {
			if(acc.Related_Company__c != null && (Teigger.isInsert || acc.Related_Company__c != Trigger.oldMap.get(acc.Id).Related_Company__c)) {
				Company__c tempComp = compMap.get(acc.Related_Company__c);
				acc.Industry__c = tempComp.Industry__c;
				acc.LinkedIn__c = tempComp.LinkedIn__c;
				acc.Size__c = tempComp.Size__c;
			}
		}
	}
}

Please do let me know if it helps you.

FYI: if you want to get information from Parent object then you can also use formula fields until unless if you want to update them as later point.

Regards,
Mahesh
James LoghryJames Loghry
You have the generally right idea.  __r is used to select a related field based on the object you're querying.  However, the object you're querying will have the __c suffix if it's a custom object or no suffix at all if it's a standard object.

Typically, you could use  a query like:
 
List<Account> account = [Select Related_Company__r.LinkedIn__c From Account Where Id in :Trigger.new.keySet()];

However, issuing queries in a loop is a bad practice, as you'll hit governor limits easily when dealing with Account records.

I took your example above and "bulkified" it by using sets to query for the related companies in one query, then iterating through the results to modify the account fields.
trigger updateAccountInfo on Account (before update) {
    
    
    Set<Id> companyIdSet = new Set<Id>();
    for(Account acc : Trigger.new) {
        companyIdSet.add(acc.Related_Company__c);
    }

    Map<Id,Company__c> companiesMap = new Map<Id,Company__c>([Select Industry__c,LinkedIn__c,Size__c From Company__c Where Id in :companyIdSet]);

    for(Account a : Trigger.new){
       Company__c relatedCompany = companiesMap.get(a.Related_Company__c);

       //Set the account fields to related company fields here
    }
}

 
This was selected as the best answer
James LoghryJames Loghry
I just read Mahesh's update and also agree that this may be a great candidate for a formula field or series of formula fields rather than this trigger, but it depends on your use case.  Definitely some food for thought, though.
Aaron HillAaron Hill
Thanks to all of you, I ended up going with James' Solution because it seemed like the most streamlined and it worked great. 

Just to explain a little more- the reason I didn't go with formula fields here is because I want to be able to update these fields when there isn't a related company, sometimes we just haven't added it to the db yet. 

I've made the lead standard object a child of the account standard object so I'm going to attempt to continue the chain on to leads. Again I really appreciate the assistance. Still working on the trailhead, but I look forward to being able to write apex like you guys eventually. 
Mahesh DMahesh D
Hi Aaron,

Here I would like to inform you few things here.

(1) This will work only in update scenario, that means it will not populate as part of insert.
trigger updateAccountInfo on Account (before update) {

This will work in both insert and update scenario.
trigger UpdateAccountInfo on Account (before insert, before update) {
(2) As the Company is a lookup field, there may be a null value in it.
companyIdSet.add(acc.Related_Company__c);

Here I am making sure that there is no null value and also as part of update we don't need to update the values for every Account modification. Hence added another condition to it.
 
if(acc.Related_Company__c != null && (Teigger.isInsert || acc.Related_Company__c != Trigger.oldMap.get(acc.Id).Related_Company__c)) {
           compIdSet.add(acc.Related_Company__c);
}


(3) Query is executing without any check whether it is empty the set or not.
 
Map<Id,Company__c> companiesMap = new Map<Id,Company__c>([Select Industry__c,LinkedIn__c,Size__c From Company__c Where Id in :companyIdSet]);

Checking whether the Set is empty or not. Making sure the below code executes only if the Set has some values in it.
 
if(!compIdSet.isEmpty() {
        Map<Id, Company__c> compMap = new Map<Id, Company__c>([Select Id, Name, Industry__c, LinkedIn__c, Size__c from Company where Id IN: compIdSet]);

These are some of the things which we need to consider while writing the code in trigger.

Please look into my solution as I considered all the above scenarios.

James, any thoughts on these points?


Please do let me know if it helps you.

Regards,
Mahesh