+ Start a Discussion
apsulliapsulli 

Apex Trigger to Update One Object with Fields from Another Based on a Shared Field

This should be a relatively simple request I think, but I can't find another example that has the specifics I need.

 

I would like to update one object based on changes made to another object where one string is equivalent.  In this case, I have a custom object (Customobj__c) that has a trigger on it to update a case with fields from that custom object based on a field that they both have in common.  One of the fields I want to update is a multi-select picklist, too (Event_Types__c).  The primary weirdness I am encountering is that the multi-select picklist doesn't always update when I save the Custom Object record, but I also suspect my code isn't laid out efficiently.  Can anyone help?

 

Here's the code:

 

trigger OnCustobjCaseFields on Customobj__c (before insert, before update)
{
String objSharedField; String objRecordId; String objAccount; String objEventTypes; for(Customobj__c obj: Trigger.new) { if (obj.Shared_Field__c != Null) { objSharedField = obj.Shared_Field__c; objRecordId = obj.Id; objAccount = obj.Account__c; objEventTypes = obj.Event_Types__c; } } List<Case> cases = new List<Case>([SELECT Id, Shared_Field__c, AccountId, Expected_Event_Types__c FROM Case WHERE Shared_Field__c = :objSharedField]); List<Case> caseUpdateList = new List<Case>(); for(Case c: cases) { c.AccountId = objAccount; c.App__c = objRecordId; c.Expected_Event_Types__c = objEventTypes; caseUpdateList.add(c); } if(caseUpdateList.size() > 0) { update caseUpdateList; } }

 

Best Answer chosen by Admin (Salesforce Developers) 
JPClark3JPClark3

First, it is normally better to update other objects in an "after" trigger. If this runs in the before insert, the OBJ.ID will be null.

 

Also, the way this is currently written, you will only get the last updated/inserted custom object to work correctly. You'll need to "bulkify" this to work for the whole list of custom objects.

 

 

trigger OnCustobjCaseFields on Customobj__c (after insert, after update)
{
    map<string, Customobj__c> ObjMap = new map<string, Customobj__c>();
    
    for(Customobj__c obj: Trigger.new)
    {
        if (obj.Shared_Field__c != Null)
        {
            ObjMap.put(obj.Shared_Field__c, obj);
        }
    }
    
    List<Case> cases = [SELECT Id, Shared_Field__c, AccountId, Expected_Event_Types__c 
    					FROM Case WHERE Shared_Field__c IN :ObjMap.KeySet()];
    List<Case> caseUpdateList = new List<Case>();
    
    for(Case c: cases)
    {
    	Customobj__c obj = ObjMap.get(c.Shared_Field__c);
        c.AccountId = obj.Account__c;
        c.App__c = obj.Id;
        c.Expected_Event_Types__c = obj.Event_Types__c;
        caseUpdateList.add(c);
    }
    
    if(caseUpdateList.size() > 0)
    {
        update caseUpdateList;
    }
}

 

All Answers

JPClark3JPClark3

First, it is normally better to update other objects in an "after" trigger. If this runs in the before insert, the OBJ.ID will be null.

 

Also, the way this is currently written, you will only get the last updated/inserted custom object to work correctly. You'll need to "bulkify" this to work for the whole list of custom objects.

 

 

trigger OnCustobjCaseFields on Customobj__c (after insert, after update)
{
    map<string, Customobj__c> ObjMap = new map<string, Customobj__c>();
    
    for(Customobj__c obj: Trigger.new)
    {
        if (obj.Shared_Field__c != Null)
        {
            ObjMap.put(obj.Shared_Field__c, obj);
        }
    }
    
    List<Case> cases = [SELECT Id, Shared_Field__c, AccountId, Expected_Event_Types__c 
    					FROM Case WHERE Shared_Field__c IN :ObjMap.KeySet()];
    List<Case> caseUpdateList = new List<Case>();
    
    for(Case c: cases)
    {
    	Customobj__c obj = ObjMap.get(c.Shared_Field__c);
        c.AccountId = obj.Account__c;
        c.App__c = obj.Id;
        c.Expected_Event_Types__c = obj.Event_Types__c;
        caseUpdateList.add(c);
    }
    
    if(caseUpdateList.size() > 0)
    {
        update caseUpdateList;
    }
}

 

This was selected as the best answer
apsulliapsulli
Fantastic, thank you! This works perfectly.
Elise FantoniElise Fantoni
I am trying to do a similar thing, but using the PS project # on the PS custom object and relate it to all the fields on the case. PS project # on the custom object maps to PS Project on the case. 
I am testing it out with the PS type field that they share for both and am getting this error "unexpected token on line 9" and that the variable "cases" does not exist



trigger PS_Project_Update_Case on PS_Project__c (after insert, after update)
{
    map<string, PS_Project__c > ObjMap = new map <string, PS_Project__c> ();
    for(PS_Project__c obj: Trigger.new){
        if (obj.Project_Type__c != Null){
            ObjMap.put(obj.Project_Type__c, obj);
        }
    }
    List<Case> cases = [SELECT Id, Project_Type__c, PS_Project_Name__c, FROM Case WHERE Project_Type__c IN :ObjMap.KeySet()];
    List<Case> caseUpdateList = new List<Case>();
    for(Case c: cases)
    {
        PS_Project__c obj = ObjMap.get(c.Project_Type__c);
        c.PS_Project_Name__c = obj.Name;
        c.PS_Project__c = obj.Id;
        caseUpdateList.add(c);
    } 
    if(caseUpdateList.size() > 0)
    {
        update caseUpdateList;
    }
}
apsulliapsulli
hey @Elise - yours is just a small syntax issue. in your Case list initialization, you have an errant comma in the soql statement after 'PS_Project_Name__c'. you just need to remove that comma at the end of the list of fields being selected.
List<Case> cases = [SELECT Id, Project_Type__c, PS_Project_Name__c, FROM Case WHERE Project_Type__c IN :ObjMap.KeySet()];
should be
List<Case> cases = [SELECT Id, Project_Type__c, PS_Project_Name__c FROM Case WHERE Project_Type__c IN :ObjMap.KeySet()];
ParidhiBindalParidhiBindal
Hi I am writing my first trigger. Please help.
I have two objects - CourseOffering and CourseConnection, there is a field in CourseOffering named 'Faculty. I want to write a trigger by which on updating Faculty, Course Connection's field named 'Status' changes to 'Former' from 'Current'.
apsulliapsulli
@Paridhi I would strongly advise using Process Builder to accomplish that task if at all possible. Triggers come with a lot of overhead re: deployment, maintenance, and test coverage, and a best practice is to reserve them for problems that cannot be solved with declarative tools.

To answer your question, though, it depends on how the relationships are build. Does CourtOffering relate to CourseConnection or vice versa? Or are both related to a parent "Course" object of some kind? That relationship structure will drive how the trigger is formed.