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
dietcoladietcola 

count records in a related list

Hi, all-

 

Does anyone have code already written to populate a field with the count of the number of records in a particular related list on a custom object?  I've never created an Apex trigger, but I'm hoping this one would be pretty basic to deploy.

 

(A roll-up summary field doesn't work for me in this case, since the two objects I'm concerned with do not have a parent-child relationship.)

 

Thanks in advance!

sfdcfoxsfdcfox

For ease of use, I recommend two triggers. One on the child object (to cause a parent-level trigger), and a second to update the field. This generic pattern works like this:

 

 

trigger triggerParent on Child__c (after insert, after update, after delete, after undelete) {
  Map<Id,Parent__c> parents = new Map<Id,Parent__c>();
  if(Trigger.new<>null)
    for(Child__c c:Trigger.new)
      if(c.ParentLookup__c<>null)
        parents.put(c.ParentLookup__c,new Parent__c(id=c.ParentLookup__c));
  if(Trigger.old<>null)
    for(Child__c c:Trigger.old)
      if(c.ParentLookup__c<>null)      
        parents.put(c.ParentLookup__c,new Parent__c(id=c.ParentLookup__c));
  update parents.values();
}

 

trigger rollupChildren on Parent__c (before insert, before update) {
  for(Parent__c p:Trigger.new)
    p.RollupCounter__c = 0;
  for(Child__c c:[select id,ParentLookup__c from Child__c where ParentLookup__c in :Trigger.new])
    Trigger.newMap.get(c.ParentLookup__c).RollupCounter__c++;
}

The child trigger is responsible for making sure that both the old parent and new parent (if there is change) has their values updated accordingly. The parent trigger actually performs the tallying.

 

 

Unlike a regular rollup summary field, you must run a data loader job against all existing records to update the values.

dietcoladietcola

It may just be my issue plugging incorrect values into your code, but I can't get it to compile.

 

I should have specified before, though--I'm trying to get a count on my "child" object exactly how many times each child record has been assigned to any "parent" record.  Will your code suffice for that scenario?  I'm wondering if the references to the lookup fields should be moved to the other trigger, and that's why it won't compile.

 

Thanks so much for your help!

sfdcfoxsfdcfox

So, you're trying to determine... how many times "Parent__c" or some such has changed? That's something like this:

 

 

trigger updateBeanCounter on Child__c (before insert, before update)
  // For when there's no value at all, we default to zero.
  for(Child__c c:Trigger.new)
    if(c.Bean_Count__c==null)
      c.Bean_Count__c=0;
  // If parent is set, and parent has changed, increment by 1.
  // On create, if Parent__c is set, this means it will be a value
  // of 1, otherwise 0. For each update, if there is a change in
  // parent, and that change is to a non-null value, we increment
  // by 1.
  for(Child__c c:Trigger.new)
    if(c.Parent__c<>null && (Trigger.old == null || Trigger.oldMap.get(c.id).Parent__c <> c.Parent__c))
      c.Bean_Count__c++;
}

I'm not sure what your exact use case may be, but I'm trying to be as useful as possible!

 

 

dietcoladietcola

Sorry to be so vague--I definitely appreciate your help!  I was hoping to spare you from the gory details, but it seems the nature of the code requires me to be more specific than I had originally thought.

 

Here's my specific use case:

 

I have two objects: one called Items and one called Groups.  (We use these for a specific fundraiser that we track through Salesforce.)  A Group has a minimum of one Item in it, a maximum of four--so every Group record has four lookup fields to the Item object on it, though not all lookup fields are used on each Group (since some Groups only have one Item, or two, or three.)

 

Every Item must be assigned to one and only one Group.

 

What I'm ultimately hoping to create is a field called "# of groups assigned" on the Item object that will show how many times that particular Item has been used in any of the four lookup fields on all Group records.  This is to give my users a way to make sure that they've assigned every Item to one (and only one) Group record--they can just take a look at a List View or a report that shows each Item, make sure that the "# of groups assigned" field is populated with the number "1" for every Item, and know that each Item has been accounted for in a Group.

 

I planned to do this by creating four separate number fields on the Items object (that wouldn't show on any page layouts, but would just work in the background)--one to count how many times each Item has been placed on each of the four lookup fields on the Groups object.  The "# of groups assigned" field would then be a formula field that found the sum of all four of those hidden number fields.

 

I'm guessing that just one trigger could be written to add all four lookup field counts directly instead, but that seemed like it would be more complicated.  What do you think?

 

Does this makes sense?

 

Thanks so much for you help, again!

SFDummySFDummy

thanks for the sample code. works great in my scenario.

 

Custom object has Account lookup. Now I can get count of related objects on Account

Pooja BhasinPooja Bhasin
Hi sfdcfox,

Thanks for your help here.

I have a child object with a lookup on Lead and I used the code you mentioned to count records in child object.This works fine in one Oeg.
However , when I deploy in another I get the error while creating leads as below :

Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger Onchild caused an unexpected exception, contact your administrator: Onchild: execution of BeforeInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.Onchild: line 5, column 1

This is what I wrote :

trigger Onchild on Lead (before insert, before update) {
  for(Lead p:Trigger.new)
    p.Calls_Made__c = 0;
  for(Lead_Call_Tracker__c c:[select id,Lead_sfdc_test__c from Lead_Call_Tracker__c where Lead_sfdc_test__c in :Trigger.new])
    Trigger.newMap.get(c.Lead_sfdc_test__c).Calls_Made__c++;
}

Please suggest.
John Dray 4John Dray 4
sfdcfox, I did find that you could get a null exception error. Adding the following in between line 4 and 5 of the parent trigger fixed this:

    if(c.ParentLookup__c != null)

Otherwise very helpful - got me out of a hole!
Shibasish SahaShibasish Saha

sfdcfox & John Dray 4... Thanks sir. It helped a lot.