The getRefRecord dilemma

General Add comments
by:


The getRefRecord functionality in ServiceNow is a function that gets a GlideRecord object for a given reference element. But what does it actually do and how should it be used in Istanbul and higher?

Let’s take a look at the following example: From the change task we want to update the ‘counter’ field on the change request by using an After Business Rule. There is a catch, there are Business Rules running on table Change Request that trigger on update.

Table Field Referenced table Referenced field
Change Task Change Request Change Request Counter

 

Business Rule name Table After/Before When to Run Action
Update Counter on Change Request Change Task 250 Update Update the counter field
Update Fields Change Request 100 Insert/Update Update the short description, description, and reason.

In the GlideRecord way that would be. (A get is also applicable):

var changeTask = new GlideRecord(“change_task”);
changeTask.addQuery("sys_id", "xxx");
changeTask.query();

if(changeTask.next()){
var changeRequest = changeTask.change_request.getRefRecord();
changeRequest.counter = 2;
changeRequest.update();
}

Expected Result:
What people expect is that only the counter field on the Change Request is updated. But also the short description, description and reason. This does not happen.

What actually happens:
Because of the processing order and how getRefRecord works the following happens:
1. Business rule “Update Counter on Change Request”: GetRefRecord stores a copy of the Change Request record in the variable “changeRequest”.
2. Business rule “Update Fields”: Update fields on Change Request changes the short description, description, and reason.
3. Business rule “Update Counter on Change Request”: executes the update function.

Result:
The stored object in variable “changeRequest” is set over the Change Request record. This will remove the updates made by Business rule “Update Fields”.

Correct use:
In the Business rule “Update Counter on Change Request” use a new GlideRecord call:

var changeTask = new GlideRecord(“change_task”);
changeTask.addQuery("sys_id", "xxx");
changeTask.query();

if(changeTask.next()){
var changeRequest = new GlideRecord("chnage_request");
changeRequest.addQuery("sys_id", changeTask.change_request);
changeRequest.query();

if(changeRequest.next){
changeRequest.counter = 2;
changeRequest.update();
}
}

Using the new GlideRecord call gets the version that has the updates that have been made by other Business Rule.

Extra:
Because of the way processing and handling of objects in the memory work, more unexpected behaviour can happen. Picture the following:
1. A script include function (a) updates a CI name via GlideRecord.
2. Function a gets aborted by a business rule because of a duplicate CI name.
3. The same script include function (b) stores the record via getRefRecord. This is not for updating but for logging purposes.
4. The name of the CI in function b is the new value used in function a.  This is not what was expected. Here is where processing comes in. Expected was the old name since step 2 aborted it.

Keep in mind to always to get the record again to prevent these unexpected behaviors.
.img[at].img

Leave a Reply