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
Michael LudwigMichael Ludwig 

Before insert trigger creates new record but sets checkbox to true where it should be false

Hi,

I came across a strange behavior when writing a trigger, not sure if I am missing the obvious somewhere.
Here is the situation:
We have a custom object called Interest_Tag__c. Among other information, the record has a checkbox which by default is set to false.
The process is the following:
As soon as a record of record type 'Raw data' is created, some of the information from that record is used to create a new Interest_Tag__c record, but with a different record type. Both records exist in the system later, however, the 'Raw data' record type should have the checkbox set to 'true', while the second Interest_tag__c record should have the checkbox set to 'false'.
Below is the basic structure for the trigger I am testing at the moment, you see the portion for 'Before Insert'.
it.Completely_Converted__c = true should update the record with the 'Raw data' record type, I also explicitely set NewActTag.Completely_Converted__c= false and the debug statement for TagsToCreate shows completely_converted = false for the second record.
When trying to insert a new record of type 'Raw Data', two records are created with different record types (works as planned), but both of them have the checkbox set to true.
When commenting out it.Completely_Converted__c = true, both records have the checkbox unchecked.

Any hint would be appreciated, maybe I don't seethe wood for the trees :-)
IF(Trigger.isBefore && Trigger.isInsert){
        
        Set<String> ActivityParts = new Set<String>();
        Set<ID> ActivityGPLID = new Set<ID>();
        Map<String, RecordType> rtMap = new Map<String, RecordType>();
        String rt;
        Map<String, Contact> Contacts = new Map<String, Contact>();
        Set<String> TagEmails = new Set<String>();
        Interest_Tag__c NewActTag = new Interest_Tag__c();
        List<Product_Hierarchy__c> ProductHierarchyList= new List<Product_Hierarchy__c>();
        Map<String, Part__c> TagParts = new Map<String, Part__c>();
        List<Interest_Tag__c> TagsToCreate = new List<Interest_Tag__c>();
        
        FOR(RecordType rt1 : [SELECT Name FROM RecordType WHERE SobjectType ='Interest_Tag__c']){
            rtMap.put(rt1.Name, rt1);
        }
        
        FOR(Interest_Tag__c it : Trigger.New){
            IF(it.Record_Type_Name__c == 'Raw Data' && it.Completely_Converted__c == false){
                ActivityParts.add(it.Part_Number_Text__c);
                TagEmails.add(it.Email_from_Activity_or_Contact_Role__c);    
            }
            FOR(Part__c p1 :[SELECT Product_Hierarchy__c, Name FROM Part__c WHERE Part__c.Name in :ActivityParts] ){
                ActivityGPLID.add(p1.Product_Hierarchy__c); 
                Tagparts.put(p1.Name, p1);
            }
            FOR(Product_Hierarchy__c ph1 :[SELECT ID, Name FROM Product_Hierarchy__c WHERE ID in :ActivityGPLID] ){
                ProductHierarchyList.add(ph1); 
            }
            FOR(Contact con1 :[SELECT email FROM Contact WHERE Email in :TagEmails]){
                Contacts.put(con1.Email, con1);
            }
            
            IF(it.Activity_Rating_Desc__c=='3D PDF'){
                rt = rtMap.get('Interest Tag Final 3D PDF').id;
            }ELSE
                IF(it.Activity_Rating_Desc__c=='Sample request'){
                    rt = rtMap.get('Interest Tag Final Sample Request').id;    
                }ELSE
                    IF(it.Activity_Rating_Desc__c=='CAD Model'){
                        rt = rtMap.get('Interest Tag Final CAD').id;   
                    }
            For (Product_Hierarchy__c ph2 :ProductHierarchyList){
                NewActTag.RecordTypeId= rt;
                
                NewActTag.Area_of_Interest__c = ph2.Name;
                NewActTag.Contact__c = Contacts.get(it.Email_from_Activity_or_Contact_Role__c).id;
                NewActTag.Part__c = Tagparts.get(it.Part_Number_Text__c).id;
                NewActTag.GPL__c = ph2.Id;
                NewActTag.Completely_Converted__c= false;
                TagsToCreate.add(NewActTag);
            }
            
            it.Completely_Converted__c = true;
        }
        Insert TagsToCreate;
        System.debug(TagsToCreate);
    }

 
Best Answer chosen by Michael Ludwig
Nayana KNayana K
Hi,

SOQL query inside for loop is a BIG NO. Should never do that.
Try below code and let me know if something is not working.
IF(Trigger.isBefore && Trigger.isInsert)
{ 
	Set<String> ActivityParts = new Set<String>();
	Set<ID> ActivityGPLID = new Set<ID>();
	Map<String, RecordType> rtMap = new Map<String, RecordType>();
	Id rt;
	Map<String, Contact> Contacts = new Map<String, Contact>();
	Set<String> TagEmails = new Set<String>();
	Interest_Tag__c NewActTag;
	Map<String, Part__c> TagParts = new Map<String, Part__c>();
	List<Interest_Tag__c> TagsToCreate = new List<Interest_Tag__c>();
	Map<String, Set<Id>> mapActPartToPHId = new Map<String, Set<Id>>();
	Map<Id, Product_Hierarchy__c> mapPH;
	
	FOR(RecordType rt1 : [SELECT Name FROM RecordType WHERE SobjectType ='Interest_Tag__c'])
	{
		rtMap.put(rt1.Name, rt1);
	}
	
	FOR(Interest_Tag__c it : Trigger.New)
	{
		/* Here I have changed the condition from it.Record_Type_Name__c == 'Raw Data' to it.RecordtypeId == rtMap.get('Raw Data').id thinking that it is one of the record type. Change to old line if you feel this isn't going to work*/
		IF(it.RecordtypeId == rtMap.get('Raw Data').id  && !it.Completely_Converted__c)
		{
			if(String.isNotBlank(it.Part_Number_Text__c))
				ActivityParts.add(it.Part_Number_Text__c);
			if(String.isNotBlank(it.Email_from_Activity_or_Contact_Role__c))
				TagEmails.add(it.Email_from_Activity_or_Contact_Role__c);   
             it.Completely_Converted__c = true; 
		}
	}
	
	/* Product_Hierarchy__c != NULL condition not needed if Product_Hierarchy__c is Master-Detail*/
	FOR(Part__c p1 :[SELECT Product_Hierarchy__c, Name FROM Part__c WHERE Part__c.Name IN :ActivityParts AND Product_Hierarchy__c != NULL] )
	{
		if(mapActPartToPHId.containsKey(p1.Part__c.Name))
		{
			mapActPartToPHId.get(p1.Part__c.Name).add(p1.Product_Hierarchy__c);
		}
		else
		{
			mapActPartToPHId.put(p1.Part__c.Name, new Set<Id>{p1.Product_Hierarchy__c});
		}
		
		ActivityGPLID.add(p1.Product_Hierarchy__c); 
		Tagparts.put(p1.Name, p1);
	}
	
	mapPH =  = new  Map<Id, Product_Hierarchy__c>([SELECT ID, Name FROM Product_Hierarchy__c WHERE ID IN : ActivityGPLID]); 
	
	FOR(Contact con1 :[SELECT email FROM Contact WHERE Email in :TagEmails])
	{
		Contacts.put(con1.Email, con1);
	}
	
	FOR(Interest_Tag__c it : Trigger.New)
	{
		rt = NULL;
		if(mapActPartToPHId.containsKey(it.Part_Number_Text__c))
		{
			IF(it.Activity_Rating_Desc__c=='3D PDF')
			{
				rt = rtMap.get('Interest Tag Final 3D PDF').id;
			}ELSEIF(it.Activity_Rating_Desc__c=='Sample request')
			{
				rt = rtMap.get('Interest Tag Final Sample Request').id;    
			}ELSEIF(it.Activity_Rating_Desc__c=='CAD Model')
			{
				rt = rtMap.get('Interest Tag Final CAD').id;   
			} 
			For(Id idPH :mapActPartToPHId.get(it.Part_Number_Text__c))
			{
				NewActTag = new Interest_Tag__c();
				NewActTag.RecordTypeId= rt;
				NewActTag.Area_of_Interest__c = mapPH.get(idPH).Name;
				NewActTag.Contact__c = Contacts.get(it.Email_from_Activity_or_Contact_Role__c).id;
				NewActTag.Part__c = Tagparts.get(it.Part_Number_Text__c).id;
				NewActTag.GPL__c = idPH;
				NewActTag.Completely_Converted__c= false;
				TagsToCreate.add(NewActTag);
			}
            
		}
	}	
	
	if(!TagsToCreate.isEmpty())
		Insert TagsToCreate;
	System.debug(TagsToCreate);
}


What's the default record type of Interest_Tag__c?

All Answers

Michael LudwigMichael Ludwig
....ahh, I think I found it myself....recursive trigger, it gets fired again and I set the brackets wrong so that the record type of the new record would be excluded.
Nayana KNayana K
Hi,

SOQL query inside for loop is a BIG NO. Should never do that.
Try below code and let me know if something is not working.
IF(Trigger.isBefore && Trigger.isInsert)
{ 
	Set<String> ActivityParts = new Set<String>();
	Set<ID> ActivityGPLID = new Set<ID>();
	Map<String, RecordType> rtMap = new Map<String, RecordType>();
	Id rt;
	Map<String, Contact> Contacts = new Map<String, Contact>();
	Set<String> TagEmails = new Set<String>();
	Interest_Tag__c NewActTag;
	Map<String, Part__c> TagParts = new Map<String, Part__c>();
	List<Interest_Tag__c> TagsToCreate = new List<Interest_Tag__c>();
	Map<String, Set<Id>> mapActPartToPHId = new Map<String, Set<Id>>();
	Map<Id, Product_Hierarchy__c> mapPH;
	
	FOR(RecordType rt1 : [SELECT Name FROM RecordType WHERE SobjectType ='Interest_Tag__c'])
	{
		rtMap.put(rt1.Name, rt1);
	}
	
	FOR(Interest_Tag__c it : Trigger.New)
	{
		/* Here I have changed the condition from it.Record_Type_Name__c == 'Raw Data' to it.RecordtypeId == rtMap.get('Raw Data').id thinking that it is one of the record type. Change to old line if you feel this isn't going to work*/
		IF(it.RecordtypeId == rtMap.get('Raw Data').id  && !it.Completely_Converted__c)
		{
			if(String.isNotBlank(it.Part_Number_Text__c))
				ActivityParts.add(it.Part_Number_Text__c);
			if(String.isNotBlank(it.Email_from_Activity_or_Contact_Role__c))
				TagEmails.add(it.Email_from_Activity_or_Contact_Role__c);   
             it.Completely_Converted__c = true; 
		}
	}
	
	/* Product_Hierarchy__c != NULL condition not needed if Product_Hierarchy__c is Master-Detail*/
	FOR(Part__c p1 :[SELECT Product_Hierarchy__c, Name FROM Part__c WHERE Part__c.Name IN :ActivityParts AND Product_Hierarchy__c != NULL] )
	{
		if(mapActPartToPHId.containsKey(p1.Part__c.Name))
		{
			mapActPartToPHId.get(p1.Part__c.Name).add(p1.Product_Hierarchy__c);
		}
		else
		{
			mapActPartToPHId.put(p1.Part__c.Name, new Set<Id>{p1.Product_Hierarchy__c});
		}
		
		ActivityGPLID.add(p1.Product_Hierarchy__c); 
		Tagparts.put(p1.Name, p1);
	}
	
	mapPH =  = new  Map<Id, Product_Hierarchy__c>([SELECT ID, Name FROM Product_Hierarchy__c WHERE ID IN : ActivityGPLID]); 
	
	FOR(Contact con1 :[SELECT email FROM Contact WHERE Email in :TagEmails])
	{
		Contacts.put(con1.Email, con1);
	}
	
	FOR(Interest_Tag__c it : Trigger.New)
	{
		rt = NULL;
		if(mapActPartToPHId.containsKey(it.Part_Number_Text__c))
		{
			IF(it.Activity_Rating_Desc__c=='3D PDF')
			{
				rt = rtMap.get('Interest Tag Final 3D PDF').id;
			}ELSEIF(it.Activity_Rating_Desc__c=='Sample request')
			{
				rt = rtMap.get('Interest Tag Final Sample Request').id;    
			}ELSEIF(it.Activity_Rating_Desc__c=='CAD Model')
			{
				rt = rtMap.get('Interest Tag Final CAD').id;   
			} 
			For(Id idPH :mapActPartToPHId.get(it.Part_Number_Text__c))
			{
				NewActTag = new Interest_Tag__c();
				NewActTag.RecordTypeId= rt;
				NewActTag.Area_of_Interest__c = mapPH.get(idPH).Name;
				NewActTag.Contact__c = Contacts.get(it.Email_from_Activity_or_Contact_Role__c).id;
				NewActTag.Part__c = Tagparts.get(it.Part_Number_Text__c).id;
				NewActTag.GPL__c = idPH;
				NewActTag.Completely_Converted__c= false;
				TagsToCreate.add(NewActTag);
			}
            
		}
	}	
	
	if(!TagsToCreate.isEmpty())
		Insert TagsToCreate;
	System.debug(TagsToCreate);
}


What's the default record type of Interest_Tag__c?
This was selected as the best answer
Michael LudwigMichael Ludwig
Hi Nayana,

Thank you very much for taking the time to go through the code. I am relatively new to APEX and, of course, I fell into the stupid trap again to have the queries inside the Trigger.New loop. Going through your code I learned (/got reminded of) a lot of best practices :-)
Nayana KNayana K
Most welcome :)