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
AlSawtoothAlSawtooth 

Straightforward field update trigger

My trigger seems to work in the debug log but doesn't update the value in the UI - I have no idea why! There is a lookup on the Opp to a custom Segment object; I'm trying to update the Source Code from the Segment onto a Source Code field on the Opp.
 
trigger UpdateSourceCode on Opportunity (before insert, before update) {

List<Opportunity> opp = [select Id, Segment__c 
                                            from Opportunity 
                                            where Id in :trigger.new and Source__c = null and Segment__c != null];
                                            
List<Segment__c> segments = [select Id, Source_Code__c 
                                            from Segment__c 
                                            where Source_Code__c != null];

Map<Id, Segment__c> segmap = new Map<Id, Segment__c>(segments);

for(Opportunity o : opp){
    if(segmap.containskey(o.Segment__c)){
    System.debug('Does segmap contain key: ' + segmap.containskey(o.Segment__c));
        List<Segment__c> OneSeg = [select Source_Code__c from Segment__c];
        System.debug('oneseg size: ' + OneSeg.size());
        if(OneSeg.size()>0){
            o.Source__c = OneSeg[0].Source_Code__c;
            System.debug('opp source code: ' + o.Source__c);
            System.debug('effort segment source code: ' + OneSeg[0].Source_Code__c);
            //these two debugs are the same (correct) value - so why isn't it updating?
              }
        }    
    }

}

 
Best Answer chosen by AlSawtooth
SarfarajSarfaraj
Hi

Firstly I am not seeing any reason why it is not working. It should work. Secondly I could not resist to optimize/bulkify your code. Here is what I would write,
trigger UpdateSourceCode on Opportunity (before insert, before update) {
	List<Id> segmentIds = new List<Id>();
	List<Opportunity> oppList = new List<Opportunity>();
	for(Opportunity opp : Trigger.new)
		if(opp.Source__c == null && opp.Segment__c != null)
		{
			segmentIds.add(opp.Segment__c);
			oppList.add(opp);
		}
	Map<Id, Segment__c> segmentsMap = new Map<Id, Segment__c>([SELECT Id, Source_Code__c FROM Segment__c WHERE Id IN :segmentIds]);
	
	for(Opportunity opp : oppList)
		opp.Source__c = segmentsMap.get(opp.Segment__c).Source_Code__c;
	
	System.debug(oppList); //Please let me know what this line prints?
}
It is same code so the end result should be same. I think you should check for some items. 
1. See if there is any workflow rule that is causing this value to reset to null.
2. See if there is any other trigger active on the same object.
3. Check the entire log to see if there is any code that is causing any rollback of the entire update (this is applicable for update only.)
4. Double check if your are checking the correct field. You may try workbench to query related Opportunity records "Select Source__c From Opportunity Where Id='<put a Id that you updated>'.

Let me know if you find anything.

--Akram

All Answers

SarfarajSarfaraj
Hi

Firstly I am not seeing any reason why it is not working. It should work. Secondly I could not resist to optimize/bulkify your code. Here is what I would write,
trigger UpdateSourceCode on Opportunity (before insert, before update) {
	List<Id> segmentIds = new List<Id>();
	List<Opportunity> oppList = new List<Opportunity>();
	for(Opportunity opp : Trigger.new)
		if(opp.Source__c == null && opp.Segment__c != null)
		{
			segmentIds.add(opp.Segment__c);
			oppList.add(opp);
		}
	Map<Id, Segment__c> segmentsMap = new Map<Id, Segment__c>([SELECT Id, Source_Code__c FROM Segment__c WHERE Id IN :segmentIds]);
	
	for(Opportunity opp : oppList)
		opp.Source__c = segmentsMap.get(opp.Segment__c).Source_Code__c;
	
	System.debug(oppList); //Please let me know what this line prints?
}
It is same code so the end result should be same. I think you should check for some items. 
1. See if there is any workflow rule that is causing this value to reset to null.
2. See if there is any other trigger active on the same object.
3. Check the entire log to see if there is any code that is causing any rollback of the entire update (this is applicable for update only.)
4. Double check if your are checking the correct field. You may try workbench to query related Opportunity records "Select Source__c From Opportunity Where Id='<put a Id that you updated>'.

Let me know if you find anything.

--Akram
This was selected as the best answer
AlSawtoothAlSawtooth
Thank you so much for the bulkified version! I'll make sure I try all of your suggestions and keep you updated.
Craig WarheitCraig Warheit
If I understand the requirements correctly it seems as though the trigger should be on Segment__c, not on Opportunity.

Also, ask Akram mentioned, you need to bulkify your code.  Make sure there aren't any SQOL Queries in for loops, make sure you detect changes before processing code (i.e. if there isn't a change go Source_Code__c don't run queries that you don't need).  Definitely read through this: https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices

I would also strongly suggest you get this code out of a trigger and into a trigger handler class.
trigger UpdateSourceCode on Segment__c (after insert, after update) {
    //create map to hold updates.
    Map<Id, Segment__c> segmentMap = new Map<Id, Segment__c>();

    //loop through trigger.new to check for updates
    for(Segment__c seg:trigger.New){
        if((trigger.isInsert && seg.Source_Code__c != null) || (trigger.isUpdate && seg.Source_code__c != trigger.newMap(seg.id).Source_Code__c)){
            segmentMap.put(seg.id, seg);
        }
    }

    //if there are updates, get the opportunities to update and set the Source__c field
    if(!segmentMap.isEmpty()){
        List<Opportunity> opptysToUpdate = [SELECT id, Source__c, Segment__c FROM Opportunity where Segment__c in: segmentMap.keyset()];

        for(Opportunity o:opptysToUpdate){
            o.Source__c = segmentMap.get(o.Segment__c).Source_Code__c;
        }
    }

    //update the Opportunities, handle errors
    try{
        update opptysToUpdate;
    }catch(DMLException e){
        system.debug('handle error: ' + e);
    }
}

 
Balaji Chowdary GarapatiBalaji Chowdary Garapati

@AlSawtooth 

 Your code seems to be workable except the query you wrote in the for loop,not sure why you wrote a duplicate kind of query in the for loop, which will definite hit governor limit in bulk update operation with limit > 100 ?? . Can you please share the complete debug log? just to see if there is any other trigger/workflow rule is firing that over writes the value you write into the field.

Thanks,
balaj
AlSawtoothAlSawtooth
@akram, the bulkified version worked! Thank you!!
SarfarajSarfaraj
@AlSawtooth

Glad that it worked. Now I have a suggestion for you. In my opinion this kind of simple field update should be handled by workflow rules. Trigger is for advanced/complex kind of update.
AlSawtoothAlSawtooth
I didn't think this would be possible through workflow because it's a lookup field - is that not the case?
SarfarajSarfaraj
It is very much possible using Workflow rule.
  1. Create a WF rule on Opportunity.
  2. Add a criteria Source__c = null and Segment__c != null.
  3. Add a field update action. Chose field to update as Source__c and value to be a formula, Segment__r.Source_Code__c. I am assuming the relationship name to be Segment__r. If it is different please change it.
--Akram
Craig WarheitCraig Warheit
I think this could be simplified even further.  Couldn't this just be a formula field?  Create a Text formula field and then use Segment__r.Source_Code__c as the formula?
AlSawtoothAlSawtooth
Thanks for all your help!

@Craig: I'm hoping to be able to edit this field on the Opp, so a formula field won't work for me. 

@Akram: Thank you - this is perfect. I'm so glad I don't have to use code for this!! Thanks for all your help.