规则:怎样改对象与关系

第 3 课 · 共 7 课 约 8 分钟

六种规则,外键与多对多链接怎么选,一次改一批对象;规则只搬运值,不做计算。

本课目标

读完这一课,你将能够

  • 说出六种规则各改什么,并选对「改外键」还是「建链接」
  • 写出 flag-defect 与 hold-work-order 的规则
  • 说出规则做不到什么,遇到时怎么办

六种规则

参数只是输入。把输入变成对象和关系上的改动,靠规则。AIDC 的 Action 现在有六种规则:

createObject

新建对象

主键必须有值:来自参数,或写 $uuid 让平台生成。

modifyObject

修改对象

改已有对象的属性,对象来自对象参数或对象集参数,命中几个改几个。不能改主键,也不能改本次新建的对象。

createOrModifyObject

新建或修改

按主键判断:有就改,没有就建。

deleteObject

删除对象

删除对象参数指向的对象。删除只发生在 Semantic 里,数据源里的那一行不动。

createLink

建立链接

在两个对象之间建立一条多对多链接,两端都是对象参数。

deleteLink

解除链接

解除一条多对多链接。

规则里每个属性的值有四种来源:

  • 来自参数:$goodQty,取调用方填的值。
  • 来自对象参数的属性:$line.lineCode,取被选中那条产线的编码。
  • 写死的字面量:released,调用方改不了。
  • 来自上下文:$user(执行人)、$userName、$now(提交时间)、$uuid(新主键)。

modifyObject 只写要改的属性,没写的保持原样:report-output 更新累计数,不会碰工单的计划数量和产线。

下面的 create-purchase-order 把这四种来源用全了。ownerId 与 createdAt 是示例工厂的共享属性,这里假设 purchaseOrder 带着它们:

{
  "kind": "actionType",
  "apiName": "create-purchase-order",
  "title": "创建采购订单",
  "schema": {
    "parameters": [
      { "name": "supplier", "type": "object", "objectType": "supplier", "title": "供应商", "required": true },
      { "name": "material", "type": "object", "objectType": "material", "title": "物料", "required": true },
      { "name": "qty", "type": "integer", "title": "数量", "required": true, "min": 1 },
      { "name": "expectedAt", "type": "date", "title": "期望到货日", "required": true }
    ],
    "rules": [
      {
        "type": "createObject",
        "objectType": "purchaseOrder",
        "values": {
          "poNo": "$uuid",
          "status": "draft",
          "qty": "$qty",
          "expectedAt": "$expectedAt",
          "supplierId": "$supplier.supplierId",
          "materialCode": "$material.materialCode",
          "ownerId": "$user",
          "createdAt": "$now"
        }
      }
    ],
    "actionLog": true
  }
}

关系怎么改:外键还是链接

关系怎么改,取决于它怎么存。两条路别混:

一对多、一对一多对多
关系存在哪多的一端对象上的外键属性每条链接是自己的一条记录
用哪种规则createObject 或 modifyObject 写外键createLink、deleteLink
示例工厂新缺陷挂到检验上:defect.inspectionId产品和物料的 productMaterials

缺陷与检验是一对多(inspectionDefects),关系存在 defect.inspectionId 上。所以 flag-defect 新建缺陷时写好这个外键,就等于把它挂到了检验下面,不需要 createLink。severity 的三个取值(minor、major、critical)由值类型 defectSeverity 约束。多对多则不同:createLink 的两端都取自对象参数,一条链接是自己的一条记录,解除它只是删掉这条记录,两端的对象都还在。

{
  "kind": "actionType",
  "apiName": "flag-defect",
  "title": "登记缺陷",
  "schema": {
    "parameters": [
      { "name": "inspection", "type": "object", "objectType": "inspection", "title": "检验", "required": true },
      { "name": "code", "type": "string", "title": "缺陷代码", "required": true, "maxLength": 40 },
      { "name": "severity", "type": "string", "valueType": "defectSeverity", "title": "严重程度", "required": true },
      { "name": "description", "type": "string", "title": "说明", "maxLength": 200 }
    ],
    "rules": [
      {
        "type": "createObject",
        "objectType": "defect",
        "values": {
          "defectId": "$uuid",
          "code": "$code",
          "severity": "$severity",
          "description": "$description",
          "status": "open",
          "inspectionId": "$inspection.inspectionId"
        }
      }
    ],
    "summary": "检验 {inspection} 登记缺陷 {code}",
    "actionLog": true
  }
}

一次改一批,与规则的组合

质量出了问题,常常要一次暂停一批工单。这时参数用对象集,一条 modifyObject 就改掉命中的每一个对象:

{
  "kind": "actionType",
  "apiName": "hold-work-order",
  "title": "暂停工单",
  "schema": {
    "parameters": [
      { "name": "workOrders", "type": "objectSet", "objectType": "workOrder", "title": "工单", "required": true },
      { "name": "reason", "type": "string", "title": "暂停原因", "required": true, "maxLength": 200 }
    ],
    "rules": [
      { "type": "modifyObject", "objectType": "workOrder", "object": "$workOrders", "values": { "status": "paused" } }
    ],
    "actionLog": true
  }
}

reason 没有写进任何属性,但它是参数,会进日志,事后能查到「为什么暂停」。一次最多改 10,000 个对象、涉及 50 个对象类型。

一个 Action 可以放多条规则,发运订单就是「新建发运单」加「改订单状态」(第 7 节)。多条规则会被合成每个对象一条编辑:如果两条规则给同一个对象的同一个属性写值,结果就是后一条的,所以规则的顺序会影响结果,而且有三种组合不成立:

  • 先删除、再新增或修改同一个对象。
  • 先修改、再新增同一个对象。
  • 同一次提交里新建同一个对象两次。

规则不做什么

规则只搬运值,不做计算。receive-material 想把收到的数量加到 material.onHandQty 上,「原值加收货数」这个加法写不进规则。

  • 一种办法:调用方先算好「收货后现存量」,作为参数传入。也可以用编辑 Function 在 Action 内读取对象并计算。
  • 需要在 Action 里读多个对象再计算,是 Function 驱动的 Action 的活,第 7 节讲。
  • 主键不能用 Action 改。想换主键,就删掉这个对象再新建一个。

下面是 receive-material 使用声明式规则的写法:调用方先算好「收货后现存量」,作为 onHandQtyAfter 传入。receivedQty 留在日志里,事后能对账。两条 modifyObject 分别改采购订单和物料,在同一个事务里。

{
  "kind": "actionType",
  "apiName": "receive-material",
  "title": "收料",
  "schema": {
    "parameters": [
      { "name": "purchaseOrder", "type": "object", "objectType": "purchaseOrder", "title": "采购订单", "required": true },
      { "name": "material", "type": "object", "objectType": "material", "title": "物料", "required": true },
      { "name": "receivedQty", "type": "integer", "title": "本次收到数量", "required": true, "min": 1 },
      { "name": "onHandQtyAfter", "type": "integer", "title": "收货后现存量", "required": true, "min": 0 }
    ],
    "rules": [
      { "type": "modifyObject", "objectType": "purchaseOrder", "object": "$purchaseOrder", "values": { "status": "received" } },
      { "type": "modifyObject", "objectType": "material", "object": "$material", "values": { "onHandQty": "$onHandQtyAfter" } }
    ],
    "submissionCriteria": [
      {
        "condition": { "type": "comparison", "left": { "param": "purchaseOrder", "property": "status" }, "operator": "is", "right": { "literal": "approved" } },
        "failureMessage": "只有已批准的采购订单可以收料"
      },
      {
        "condition": { "type": "comparison", "left": { "param": "purchaseOrder", "property": "materialCode" }, "operator": "is", "right": { "param": "material", "property": "materialCode" } },
        "failureMessage": "这张采购订单采购的不是所选的物料"
      }
    ],
    "actionLog": true
  }
}

改什么、怎么改都定了,下一节讲最重要的一道关:提交条件,它决定什么时候、谁不能改。

要点

  • 六种规则:新建、修改、新建或修改、删除对象,建立、解除链接。
  • 一对多、一对一的关系改外键,多对多才用链接规则。
  • 对象集参数加一条 modifyObject,一次改一批;一次最多 10,000 个对象、50 个对象类型。
  • 规则只搬运值,不做计算。调用方可以先算好,也可以让编辑 Function 读取对象、计算并产生编辑。

练一练

为采购与工单写规则

三个小任务,从写到判断到检查。

把一张采购订单的负责人换成另一位同事:参数是采购订单和新负责人的账号(string),一条 modifyObject 改 ownerId。再想一想:这个 Action 应该加哪条提交条件,才不会有人把别人的订单抢走?

小测

选一个答案,马上看解析。

Q1flag-defect 要把新缺陷挂到一次检验上,应该怎么做?

Q2receive-material 想让 onHandQty 变成「原值加收货数量」,规则里能这样写吗?

Q3同一个 Action 里先 deleteObject 一个对象,再 modifyObject 同一个对象,会怎样?

延伸阅读