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
Richa_LearningRicha_Learning 

Validation rule in Trigger

Hi,

I am trying to add a validation rule in trigger that if

Details status = 'In Progress" then Tracker status cannot be updated to Closed.

I get this error "Comparison arguments must be compatible types: Schema.SObjectField​"
 
trigger Tracker_AfterUpdate on Tracker__c (After Update) 
{   
       
        if(Trigger.IsAfter && Trigger.IsUpdate)
        {           
            Set<Id> TrackerIDs = new set<Id>();   
                        
            for(Tracker__c Tempdata : trigger.new)
            {                 
                if(Tempdata.Status__c=='Closed' && details__c.status__c=='In progress')
                {
                Tempdata.Status__c.adderror ('not allowed');
                }                        
            }           
                      
        }
    }

Please help
Best Answer chosen by Richa_Learning
Kelly KKelly K

Sorry - one modification:

trigger Tracker_beforeUpdate on Tracker__c (before Update) {    
    if( Trigger.IsUpdate) {    
		List<Details__c> detailsList = [SELECT Id, Status__c FROM Details WHERE Tracker__c IN trigger.new];
		Map<Id, List<Details__c>> trackerToDetailsMap = new Map<Id, List<Details__c>>();
		
		for(Details__c detail : detailsList) {
			List<Details__c> trackerDetailsList = new List<Details__c>();
			
			if(trackerToDetailsMap.get(detail.Tracker__c) != null)
				trackerDetailsList = trackerToDetailsMap.get(detail.Tracker__c);
			
			trackerDetailsList.add(detail);
			trackerToDetailsMap.put(detail.Tracker__c, trackerDetailsList);
			
		}			
	
        for(Tracker__c tracker : trigger.new) {        
			if(trackerToDetailsMap.containsKey(tracker.Id) {
				for(Detail__c detail : trackerToDetailsMap.get(tracker.Id))
					if(tracker.Status__c == 'Closed' && detail.Status__c == 'In progress')
						tracker.adderror('not allowed');
			}	
        }         
    }
}

All Answers

Kelly KKelly K

On line 12 - I don't think you can add the error to a field for apex validation. If I recall correctly, addError() is only an sObject method.

Try rewriting it like this - but I would definitely give it a more descriptive error for production since the error will show at the top of the page.

Tempdate.addError('not allowed');
Richa_LearningRicha_Learning
I change it and now i am getting this error
 
Compile Error: Variable does not exist: details__c.status__c

 
Kelly KKelly K

I'm assuming details is a lookup field on the Tracker__c object? If so, then you have to treat it as a relationship.

try this:

if(Tempdata.Status__c=='Closed' && Tempdate.details__r.status__c=='In progress')
Richa_LearningRicha_Learning
Yes, it's a lookup but I am getting the same error:
 
compile Error: Variable does not exist: details__r.status__c

 
Kelly KKelly K
You need to add "Tempdata" to the beginning of it. So the full comparison is "Tempdata.details__r.status__c == "In progres".  It needs to know which record it's reading the field from.
Richa_LearningRicha_Learning
This is how it looks now:
 
trigger Tracker_beforeUpdate on Tracker__c (before Update) 
{   
       
        if( Trigger.IsUpdate)
        {           
            Set<Id> TrackerIDs = new set<Id>();   
                        
            for(Tracker__c Tempdata : trigger.new)
            {                 
                if(Tempdata.Status__c=='Closed' && tempdata.details__r.status__c=='In progress')
                {
                Tempdata.adderror ('not allowed');
                }                        
            }           
                      
        }
    }

Now I get this error:
Compile Error: Method does not exist or incorrect signature: [Tracker__c].addderror(String)

If I comment the Adderror row , I get this:
Compile Error: Invalid foreign key relationship: Tracker__c.Details__r

Details has lookup relationship to Tracker.
 
Kelly KKelly K
As far as the addError goes, let's remove the space after 'addError' so it looks like adderror('not allowed');

As far as the details - can you describe how tracker & details works in your org? id the details an object related to the tracker or is tracker related item to details? Is this a one to one relationship or a one to many?

 
Richa_LearningRicha_Learning
it's one to many. Tracker can have many details records. So i am looking a way not to close the tracker record until we close all the details record.
Richa_LearningRicha_Learning
Also, there is no space after 'AddError' in my trigger. It  may be a pasting issue. 
 
trigger Tracker_beforeUpdate on Tracker__c (before Update) 
{   
       
        if( Trigger.IsUpdate)
        {           
            Set<Id> TrackerIDs = new set<Id>();   
                        
            for(Tracker__c Tempdata : trigger.new)
            {                 
                if(Tempdata.Status__c=='Closed' && tempdata.details__r.status__c=='In progress')
                {
                Tempdata.adderror('not allowed');
                }                        
            }           
                      
        }
    }

 
Kelly KKelly K
I see. This won't work as is then. And understood on the pasting issue.

There are other options - the first and easiest I can think of depends on whether your details object is master-detail to tracker?

 
Richa_LearningRicha_Learning
No it is a lookup relationship.
Kelly KKelly K

k - so can't go the easy route to where you set up a rollup summary field and then use a traditional validation rule.

You'll need to query all of the details and put them in a list for iterating. Something like this. I haven't compiled it, so I'm not sure if any errors will pop up.

trigger Tracker_beforeUpdate on Tracker__c (before Update) {    
    if( Trigger.IsUpdate) {    
		List<Details__c> detailsList = [SELECT Id, Status__c FROM Details WHERE Tracker__c IN trigger.new];
		Map<Id, List<Details__c>> trackerToDetailsMap = new Map<Id, List<Details__c>>();
		
		for(Details__c detail : detailsList) {
			List<Details__c> trackerDetailsList = new List<Details__c>();
			
			if(trackerToDetailsMap.get(detail.Tracker__c) != null)
				trackerDetailsList = trackerToDetailsMap.get(detail.Tracker__c);
			
			trackerDetailsList.add(detail);
			trackerToDetailsMap.put(detail.Tracker__c, detail);			
		}			
	
        for(Tracker__c tracker : trigger.new) {        
			if(trackerToDetailsMap.containsKey(tracker.Id) {
				for(Detail__c detail : trackerToDetailsMap.get(tracker.Id))
					if(tracker.Status__c == 'Closed' && detail.Status__c == 'In progress')
						tracker.adderror('not allowed');
			}	
        }         
    }
}
 


 

Kelly KKelly K

Sorry - one modification:

trigger Tracker_beforeUpdate on Tracker__c (before Update) {    
    if( Trigger.IsUpdate) {    
		List<Details__c> detailsList = [SELECT Id, Status__c FROM Details WHERE Tracker__c IN trigger.new];
		Map<Id, List<Details__c>> trackerToDetailsMap = new Map<Id, List<Details__c>>();
		
		for(Details__c detail : detailsList) {
			List<Details__c> trackerDetailsList = new List<Details__c>();
			
			if(trackerToDetailsMap.get(detail.Tracker__c) != null)
				trackerDetailsList = trackerToDetailsMap.get(detail.Tracker__c);
			
			trackerDetailsList.add(detail);
			trackerToDetailsMap.put(detail.Tracker__c, trackerDetailsList);
			
		}			
	
        for(Tracker__c tracker : trigger.new) {        
			if(trackerToDetailsMap.containsKey(tracker.Id) {
				for(Detail__c detail : trackerToDetailsMap.get(tracker.Id))
					if(tracker.Status__c == 'Closed' && detail.Status__c == 'In progress')
						tracker.adderror('not allowed');
			}	
        }         
    }
}
This was selected as the best answer
Richa_LearningRicha_Learning
Thanks so much for your help!!!!!!!!!!!!!
Kelly KKelly K

Glad I could help! Good luck on the test class :)

Last thing I want to caution as it happened to me when I started out - is at some point when you get a lot of code, you're going to want to put more control on when that query fires, such as only when the tracker status changes (compare trigger.old with trigger.new to do this). Also, if you have many triggers you'll want to move this into an apex class so you can control which methods/triggers you want to fire first.