This article aims to explain what happens when an extended table record has it's Class/Task Type [sys_class_name] field updated to move the record to a different table with the extended table hierarchy, in order to aid debugging and avoid potential problems.
There are over a hundred extended tables in the instance, with over a thousand child tables. Once you understand the Extension Models, you will realize that changing this field value in effect moves the record from one table to another.
In general, these steps happen when an existing record is updated with a new Class value.
- A user or script in the instance, makes an update to an existing record. The sys_class_name value will be changed, plus potentially other fields.
- Before Update business rules run for the previous class. Engines at before 1000 also run. Async and After business rules don't run.
- GlideRecordClassSwitcher switchClass() runs:
- Does some checks
- Logs "Change in class detected, switching from: <previous.sys_class_name> to: <current.sys_class_name> sys_id: <sys_id>"
- Update any external records for multi value fields, such as Currency field values.
- Read all the record values into memory
- Delete the record from the previous class table. Without running business rules etc.
- Insert a new record using all the previous values of the original record. Without running business rules etc.
- If the old record has attachments, assign them to the new record.
- Update the newly inserted record (this is in addition to the initial update)
- Run Before Update Business Rules for the new class
- Audit the update.
- Run After Update Business Rules for the new class
Release or Environment
Given that process, it explains why the following happens:
'Before' Business Rules run Twice
- The initial update by the user or script
- Before Update business rules for the source table
- The additional update by the class changing code
- Before Update business rules for the target table
- After Update business rules for the target table
- Async Update business rules for the target table
.setWorkflow(false) will not prevent Business Rules or Auditing running
This method "Enables or disables the running of business rules that might normally be triggered by subsequent actions. If the e parameter is set to false, an insert/update will not be audited. Auditing only happens when the parameter is set to true for a GlideRecord operation."
If you do the class change update from a script, and use setWorkflow(false) before the .update(), this will only prevent the before update business rules running for the source table.
This has no effect on the additional Update() the class changing code does after inserting the new record. Before, After and Async business rules for the target table will still run for the record. There is no way to prevent that.
If batch updating a lot of records, you may want to analyse which business rules will run (using Session Debug perhaps) and De-activate long-running or potentially problematic ones while the updates run.
.autoSysFields(false) will not prevent updating the Updated/Updated By/etc. fields
This function "Enables or disables the update to the fields sys_updated_by, sys_updated_on, sys_mod_count, sys_created_by, and sys_created_on. This is often used for manually updating field values on a record while leaving historical information unchanged."
As with setWorkflow(false), this would only apply to the initial update. The subsequent insert and update are going to have new values populated. sys_created_on will be when this runs, and sys_mod_)count will be back to zero.
Data Loss - The record could be Deleted during this process, if the Insert fails
As explained above, the record is first deleted from the source table and then inserted in the target table. Various things could cause the insert to not happen, after the delete has already happened, meaning your record is now lost.
- The transaction could time out or be Cancelled by the user before the Insert happens. This was seen more often from Jakarta, but was possible prior to that too.
London and later versions should prevent this. see KB0727782: PRB1242353 When changing the class for many CIs from UI it may lead to transaction cancellation and deletion of few records
- Data Policy, with Mandatory field rules, could prevent the insert.
This is a known product defect - see KB0727701: PRB631444 Changing the sys_class_name of a record can result in the record being deleted if Mandatory fiel Data Policy prevents the insert in the target table
It can take a long time per record
A class change for a single record may take just a second, but can take minutes to run. That could be due to business rules running, and session debug would identify which to investigate.
In Jakarta (when TPP was used) and Kingston, an analysis of database logs usually shows most of the time spent doing a lot of queries on the Dictionary and related tables during the Delete step, due to the multiple additional dictionary records used by this model.
That has been improved from London by KB0681177: PRB1258222 Unnecessary updates during cmdb_ci class change from TPP change