Using the Related Collection Accessor Field to Work with Child Rows

When a parent object like TroubleTicket has a child object Activity, the parent object will have a related collection accessor field whose name you decided when you created the child object.

For example, if when creating the child Activity object for the TroubleTicket parent, you decided to name the related collection accessor field ActivityCollection, then you can write business logic in the context of the parent TroubleTicket object that works with the one or more Activity child rows. To do this, your code accesses the related collection accessor field by name like this:

// Assume code in context of TroubleTicket
// define a variable to hold activities collection
def activities = ActivityCollection_c 
// work with activities here...
Tip: Always store a child collection you want to work with in a local variable. Failure to do this will result in your code that does not behave as you expect.

The related collection accessor field returns a row iterator object, so you can use methods like those listed in the table below to work with the rows. The row iterator tracks the current row in the collection that your code is working with.

Most Commonly Used RowIterator Methods

Method Name

Description

hasNext()

Returns: - true if the row iterator has more rows to iterate over, false if there are no rows in the iterator's row set or if the iterator is already on or beyond the last row.

next()

Returns: - the next row in the row iterator

reset()

Returns: - void. Resets the row iterator to the "slot" before the first row.

first()

Returns: - the first row in the row iterator, or null if the iterator's row set is empty

Putting the commonly used row iterator methods from this table into practice, the example below shows the typical code you will use to work with the child row iterator. This example accesses the child row iterator using the related collection field's API name, and saves it in a local variable. Then, it resets the iterator so that it sits on the "slot" before the first row in the row iterator. Next, it uses a while loop in combination with the hasNext() method to iterate over each row in the row iterator.

// store the child row iterator in a local variable
def activities = ActivityCollection_c
// ensure iterator is on slot before first row
activities.reset()
// loop while there are more rows to process
while (activities.hasNext()) {
  // access the next row in the row iterator
  def curActivity = activities.next()
  // reference fields or object functions from the current row
  if (curActivity.Status_c == 'Open') {
    // do something here to the current child activity
  }
}
// to process the same row iterator again in this block of code, 
// call activities.reset() method again to reset the
// iterator to the slot before the first row

To detect whether the child row iterator is empty or not, you can use the first() method. If it returns null then the row iterator's row set is empty. As shown in the example below, if you call the first() method and there are rows in the row iterator's row set, this method sets the iterator to point at the first row. So, if your script uses the first() method, then plans to iterate over all the rows in the iterator again using the typical while( rowiterator .hasNext()) idiom, you need to call the reset() method on the row iterator to move the current row pointer back to the slot before the first row. Failure to do this could result in inadvertently not processing the first row in the row set.

def activities = ActivityCollection_c
// If there are no child activities...
if (activities.first() == null) {
   // Do something here because there are no child activities
}
else {
  // There are some child activities, call reset() to set
  // iterator back to slot before first row
  activities.reset()
  while (activities.hasNext()) {
    def curActivity = activities.next();
    // Do something here with the current activity
  }
}