business-rule-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Business Rule Best Practices for ServiceNow

ServiceNow 业务规则最佳实践

Business Rules are server-side scripts that execute when records are displayed, inserted, updated, or deleted.
Business Rules是运行在服务器端的脚本,会在记录被显示、插入、更新或删除时执行。

When to Use Each Type

各类规则的适用场景

TypeTimingUse CasePerformance Impact
BeforeBefore database writeValidate, modify current recordLow
AfterAfter database writeCreate related records, notificationsMedium
AsyncBackground (after commit)Heavy processing, integrationsNone (background)
DisplayWhen form loadsModify form display, set defaultsLow
类型执行时机适用场景性能影响
Before数据库写入前验证、修改当前记录
After数据库写入后创建关联记录、发送通知
Async后台执行(提交后)大量数据处理、系统集成无(后台运行)
Display表单加载时修改表单显示、设置默认值

Available Objects

可用对象

javascript
// In Business Rules, these are always available:
current   // The record being operated on
previous  // The record BEFORE changes (update/delete only)
gs        // GlideSystem utilities
javascript
// 在Business Rules中,以下对象始终可用:
current   // 当前操作的记录
previous  // 变更前的记录(仅更新/删除操作可用)
gs        // GlideSystem工具类

Before Business Rules

Before类型业务规则

Use for validation and field manipulation:
javascript
// Prevent update if condition not met
(function executeRule(current, previous) {
  if (current.state == 7 && previous.state != 6) {
    current.setAbortAction(true);
    gs.addErrorMessage('Must resolve before closing');
  }
})(current, previous);
javascript
// Auto-populate fields
(function executeRule(current, previous) {
  if (current.isNewRecord()) {
    current.setValue('caller_id', gs.getUserID());
    current.setValue('opened_by', gs.getUserID());
  }
})(current, previous);
Never do in Before rules:
  • Call
    current.update()
    (causes recursion!)
  • Query other tables (keep it fast)
  • External API calls
适用于验证和字段操作:
javascript
// 不满足条件时阻止更新
(function executeRule(current, previous) {
  if (current.state == 7 && previous.state != 6) {
    current.setAbortAction(true);
    gs.addErrorMessage('必须先解决才能关闭');
  }
})(current, previous);
javascript
// 自动填充字段
(function executeRule(current, previous) {
  if (current.isNewRecord()) {
    current.setValue('caller_id', gs.getUserID());
    current.setValue('opened_by', gs.getUserID());
  }
})(current, previous);
Before规则中禁止操作:
  • 调用
    current.update()
    (会导致递归!)
  • 查询其他表(保持规则高效)
  • 调用外部API

After Business Rules

After类型业务规则

Use for related record operations:
javascript
// Create child record when priority is P1
(function executeRule(current, previous) {
  if (current.priority.changesTo(1)) {
    var task = new GlideRecord('task');
    task.initialize();
    task.setValue('short_description', 'P1 Follow-up: ' + current.number);
    task.setValue('parent', current.sys_id);
    task.insert();
  }
})(current, previous);
javascript
// Update parent record
(function executeRule(current, previous) {
  var parent = new GlideRecord('problem');
  if (parent.get(current.problem_id)) {
    parent.setValue('related_incidents', parent.related_incidents + 1);
    parent.update();
  }
})(current, previous);
适用于关联记录操作:
javascript
// 当优先级变为P1时创建子记录
(function executeRule(current, previous) {
  if (current.priority.changesTo(1)) {
    var task = new GlideRecord('task');
    task.initialize();
    task.setValue('short_description', 'P1 跟进: ' + current.number);
    task.setValue('parent', current.sys_id);
    task.insert();
  }
})(current, previous);
javascript
// 更新父记录
(function executeRule(current, previous) {
  var parent = new GlideRecord('problem');
  if (parent.get(current.problem_id)) {
    parent.setValue('related_incidents', parent.related_incidents + 1);
    parent.update();
  }
})(current, previous);

Async Business Rules

Async类型业务规则

Use for heavy processing that shouldn't block the transaction:
javascript
// External integration
(function executeRule(current, previous) {
  var integrator = new ExternalSystemIntegration();
  integrator.syncIncident(current.sys_id);
})(current, previous);
javascript
// Send custom notification
(function executeRule(current, previous) {
  gs.eventQueue('incident.priority.high', current, current.assigned_to, gs.getUserID());
})(current, previous);
适用于不应阻塞事务的大量处理操作:
javascript
// 外部系统集成
(function executeRule(current, previous) {
  var integrator = new ExternalSystemIntegration();
  integrator.syncIncident(current.sys_id);
})(current, previous);
javascript
// 发送自定义通知
(function executeRule(current, previous) {
  gs.eventQueue('incident.priority.high', current, current.assigned_to, gs.getUserID());
})(current, previous);

Useful Methods

实用方法

current Methods

current对象方法

javascript
current.isNewRecord()           // True if insert
current.isValidRecord()         // True if record exists
current.getValue('field')       // Get field value
current.setValue('field', val)  // Set field value
current.setAbortAction(true)    // Cancel the operation
current.operation()             // 'insert', 'update', 'delete'
current.isActionAborted()       // Check if aborted
javascript
current.isNewRecord()           // 插入操作时返回True
current.isValidRecord()         // 记录存在时返回True
current.getValue('field')       // 获取字段值
current.setValue('field', val)  // 设置字段值
current.setAbortAction(true)    // 取消当前操作
current.operation()             // 返回操作类型:'insert', 'update', 'delete'
current.isActionAborted()       // 检查操作是否已取消

Field Change Detection

字段变更检测

javascript
current.priority.changes()        // Field changed (any value)
current.priority.changesTo(1)     // Changed TO this value
current.priority.changesFrom(3)   // Changed FROM this value
current.priority.nil()            // Field is empty
javascript
current.priority.changes()        // 字段发生变更(任意值)
current.priority.changesTo(1)     // 字段变更为指定值
current.priority.changesFrom(3)   // 字段从指定值变更
current.priority.nil()            // 字段为空

previous Comparisons

与previous对象对比

javascript
// Check if field was modified
if (current.state != previous.state) {
  gs.info('State changed from ' + previous.state + ' to ' + current.state);
}

// Check specific change
if (current.assigned_to.changes() && !previous.assigned_to.nil()) {
  gs.info('Reassignment occurred');
}
javascript
// 检查字段是否被修改
if (current.state != previous.state) {
  gs.info('状态从 ' + previous.state + ' 变更为 ' + current.state);
}

// 检查特定变更场景
if (current.assigned_to.changes() && !previous.assigned_to.nil()) {
  gs.info('发生了重新分配');
}

Condition Examples

条件示例

Use conditions to limit when the rule runs:
ConditionMeaning
current.active == true
Only active records
current.isNewRecord()
Only on insert
current.priority.changes()
Only when priority changes
gs.hasRole('admin')
Only for admins
current.assignment_group.nil()
Only when unassigned
使用条件限制规则的执行时机:
条件含义
current.active == true
仅针对活跃记录
current.isNewRecord()
仅在插入操作时执行
current.priority.changes()
仅在优先级变更时执行
gs.hasRole('admin')
仅管理员可触发
current.assignment_group.nil()
仅针对未分配组的记录

Performance Best Practices

性能优化最佳实践

  1. Use conditions - Limit when the rule runs
  2. Keep Before rules fast - No queries if possible
  3. Use Async for integrations - Don't block transactions
  4. Avoid Display rules - Slows form load
  5. Set Order - Lower numbers run first (100-500 range)
  6. Check "when to run" - insert, update, delete, query
  1. 使用条件过滤 - 限制规则的执行场景
  2. 保持Before规则高效 - 尽可能避免查询操作
  3. 集成操作使用Async规则 - 不要阻塞事务
  4. 尽量避免Display规则 - 会拖慢表单加载速度
  5. 设置执行顺序 - 数值越小越先执行(建议范围100-500)
  6. 确认“执行时机” - 插入、更新、删除、查询

Common Patterns

常见实现模式

Auto-Assignment

自动分配

javascript
// Before Insert/Update
if (current.assignment_group.changes() && !current.assignment_group.nil()) {
  var members = new GroupMembers(current.assignment_group);
  current.assigned_to = members.getNextAvailable();
}
javascript
// 插入/更新前执行
if (current.assignment_group.changes() && !current.assignment_group.nil()) {
  var members = new GroupMembers(current.assignment_group);
  current.assigned_to = members.getNextAvailable();
}

Cascade Updates

级联更新

javascript
// After Update
if (current.state.changesTo(7)) {  // Closed
  var tasks = new GlideRecord('task');
  tasks.addQuery('parent', current.sys_id);
  tasks.addQuery('state', '!=', 7);
  tasks.query();
  while (tasks.next()) {
    tasks.setValue('state', 7);
    tasks.update();
  }
}
javascript
// 更新后执行
if (current.state.changesTo(7)) {  // 已关闭
  var tasks = new GlideRecord('task');
  tasks.addQuery('parent', current.sys_id);
  tasks.addQuery('state', '!=', 7);
  tasks.query();
  while (tasks.next()) {
    tasks.setValue('state', 7);
    tasks.update();
  }
}