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
alekhya mathukumilli 28alekhya mathukumilli 28 

I need to write a trigger on child object before insert and before update to check that only one child record related to the parent has the check box to true. else throw an error on the new records

child_object__c
Parent_object__c
checkbox__c
Best Answer chosen by alekhya mathukumilli 28
Steven NsubugaSteven Nsubuga
Try this
trigger ensureOneTrueChild on child_object__c (before insert, before update){

	Set<Id> parentIds= new Set<Id>();    
    for(child_object__c cc : trigger.new) {
        if (cc.checkbox__c) {
			parentIds.add(cc.Id);
		}
    }
	List<child_object__c> cs = [SELECT Parent_object__c FROM child_object__c WHERE checkbox__c = 'true' AND Parent_object__c IN:parentIds];
	
	if (cs.size() > 0) {
		Set<Id> parentsWithTrueChildSet = new Set<Id>();
		for (child_object__c c : cs) {
			parentsWithTrueChildSet.add(c.Parent_object__c);
		}
		
		for (child_object__c cc : trigger.new) {
			if (parentsWithTrueChildSet.contains(cc.Parent_object__c)) {
				cc.addError('we already have a child set to true for this child parent');
			} 
		}
	}
}

 

All Answers

Steven NsubugaSteven Nsubuga
Try this
trigger ensureOneTrueChild on child_object__c (before insert, before update){

	Set<Id> parentIds= new Set<Id>();    
    for(child_object__c cc : trigger.new) {
        if (cc.checkbox__c) {
			parentIds.add(cc.Id);
		}
    }
	List<child_object__c> cs = [SELECT Parent_object__c FROM child_object__c WHERE checkbox__c = 'true' AND Parent_object__c IN:parentIds];
	
	if (cs.size() > 0) {
		Set<Id> parentsWithTrueChildSet = new Set<Id>();
		for (child_object__c c : cs) {
			parentsWithTrueChildSet.add(c.Parent_object__c);
		}
		
		for (child_object__c cc : trigger.new) {
			if (parentsWithTrueChildSet.contains(cc.Parent_object__c)) {
				cc.addError('we already have a child set to true for this child parent');
			} 
		}
	}
}

 
This was selected as the best answer
Glyn Anderson (Slalom)Glyn Anderson (Slalom)
Steven's solution works unless you are inserting/updating two or more children with the checkbox set to the same parent.  It only catches the problem if there the parent already has children in the database with the checkbox checked.

In this trigger, the first for-loop groups all of the child records with the checkbox set by their parent IDs.  The second for-loop adds an error to child records if two or more are being inserted onto the same parent.  After the second for-loop, the map contains only lists with a single child record in them.  The third for-loop uses an aggregate query to find any parent records that already have child records with the checkbox set, and adds an error to the child records that are being inserted onto those parents.
trigger EnsureOneTrueChild on Child_Object__c ( before insert, before update )
{
    String errorMessage = 'Parents can only have one Child with Checkbox set.';

    Map<Id,List<Child_Object__c>> childrenByParentId = new Map<Id,List<Child_Object__c>>();

    for ( Child_Object__c child : Trigger.new )
    {
        if ( child.Checkbox__c != true ) continue;
        if ( !childrenByParentId.containsKey( child.Parent_Object__c ) )
        {
            childrenByParentId.put( child.Parent_Object__c, new List<Child_Object__c>() );
        }
        childrenByParentId.get( child.Parent_Object__c ).add( child );
    }

    Set<Id> parentsToRemove = new Set<Id>();
    for ( Id parentId : childrenByParentId.keySet() )
    {
        List<Child_Object__c> children = childrenByParentId.get( parentId );
        if ( children.size() > 1 )
        {
            for ( Child_Object__c child : children )
            {
                child.addError( errorMessage );
            }
            parentsToRemove.add( parentId );
        }
    }
    childrenByParentId.keySet().removeAll( parentsToRemove );

    if ( childrenByParentId.isEmpty() ) return;

    for ( AggregateResult result :
        [   SELECT  COUNT(Id), Parent_Object__c
            FROM    Child_Object__c
            WHERE   (   Parent_Object__c IN :childrenByParentId.keySet()
                    AND Checkbox__c = true
                    )
            GROUP BY Parent_Object__c
        ]
        )
    {
        for ( Child_Object__c child : 
                childrenByParentId.get( (Id) result.get( 'Parent_Object__c' ) )
            )
        {
            child.addError( errorMessage );
        }
    }
}