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
Otto2020Otto2020 

Apex Class to look up a related list on a custom object and return an error if there's more than one record

I have a custom agreement object that is associated to a custom order object which shows up as a related list on the agreement. 

I would like to write a line of apex code that: upon save ie before update of the agreement , check the order related list, and if there is more than one order in it, then, throw an error asking the user to remove all other oder records, except for the latest one.

Only allow the user to save the record after this action is taken

Any ideas on how I can write this line of code?
Nathan EhrmannNathan Ehrmann
*** TRIGGER ***

trigger ContractTrigger on Contract (before update){
	
	ContractHelper.checkOrders(Trigger.newMap);

}

*** END TRIGGER ***

*** HELPER CLASS ***

public class ContractHelper{
	
	public static void checkOrders(Map<Id, Contract> cMap){
		
		List<AggregateResult> orderCounts = [SELECT COUNT(Id)ocount, Contract__c FROM Order__c 
							WHERE Contract__c 
     							IN :cMap.keys();
							GROUP BY Contract__c];

		for(AggregateResult oc : orderCounts){
			if(cMap.containsKey(oc.get('Contract__c')) && oc.get('ocount') > 1){
				cMap.get(oc.get('Contract__c')).addError('This Contract has more than one Order. Delete all previous Orders before proceeding.');
			}
		}
	}
}

*** END HELPER CLASS ***

Hi Otto. What the above does is pass the newMap (Trigger context variable) into a helper class which then fetches the Order Counts using a SOQL query and determines if any of them are too large. Feel free to contact me directly if I can help clarify.
Otto2020Otto2020
@Nathan Thanks!! This got me started and here is what I ened up with:
// Validate Orders related to agreement
        
       List<Apttus_Config2__Order__c> orderCounts = [SELECT Apttus_CMConfig__AgreementId__c FROM Apttus_Config2__Order__c WHERE Apttus_CMConfig__AgreementId__c IN :mapInAgreementOld.keyset()];
      
       for(Apttus_Config2__Order__c oc : orderCounts)
       {
           ID CID =  oc.Apttus_CMConfig__AgreementId__c;
           integer i = 0;
           for(Apttus_Config2__Order__c oc1 : orderCounts)
           {
               if (CID == oc1.Apttus_CMConfig__AgreementId__c)
               {
                    i = i + 1;
               
               }
           
           }
           if (i > 1)
           {
                  oc.addError('This Contract has more than one Order. Delete all previous Orders before proceeding.');
           }

Now 'm getting this error:

User-added image

I think if I can solve for this then the above code is good?
Abhishek BansalAbhishek Bansal
Hi Otto,

You are adding the error message on the Apttus_Config2__Order__c object which is not a valid case. You can only add the error message on the trigger context objects. You can use the below code for your requirement:
trigger validateOrders on Apttus_CMConfig__AgreementId__c(before update){
	Map<Id, Apttus_CMConfig__AgreementId__c> mapOfAgreements = new Map<Id, Apttus_CMConfig__AgreementId__c>([Select id, (Select id from FROM Apttus_Config2__Orders__r) from Apttus_CMConfig__AgreementId__c where Id IN :trigger.new]);
	
	for(Apttus_CMConfig__AgreementId__c agreement : trigger.new) {
		if(mapOfAgreements.get(agreement.Id).Apttus_Config2__Orders__r.size() > 1){
			agreement.addError('This Contract has more than one Order. Delete all previous Orders before proceeding.');
		}
	}
}

//Here Apttus_Config2__Orders__r is the child relationship name which can be different in your org. Please take care of the API names

Please let me know if you need any other help on this.

Thanks,
Abhishek Bansal.

Glyn Anderson (Slalom)Glyn Anderson (Slalom)
Otto, By using the aggregate query as Nathan suggests, and adding a HAVING clause, you can get a very concise version of the trigger:

<pre>
trigger validateOrders on Apttus_CMConfig__AgreementId__c( before update )
{
    for ( AggregateResult result :
        [   SELECT  COUNT(Id), Apttus_CMConfig__AgreementId__c
            FROM    Apttus_Config2__Order__c
            WHERE   Apttus_CMConfig__AgreementId__c IN :Trigger.new
            GROUP BY Apttus_CMConfig__AgreementId__c
            HAVING  COUNT(Id) > 1
        ]
        )
    {
        Trigger.newMap.get( (Id) result.get( 'Apttus_CMConfig__AgreementId__c' ) )
            .addError( 'Your error message here.' );
    }
}
</pre>