属性与基础类型
全部基础类型的一张表;哪些能做主键和标题键;小数、日期、数组、布尔的取值与坑。

本课目标
读完这一课,你将能够
- 说出属性带哪些元数据,写对一个属性的定义
- 用基础类型表判断一个类型能不能做主键或标题键
- 写出小数、日期、数组、布尔的取值,避开各自的坑
属性是什么
上一节定好了对象类型的骨架,这一节看骨架上的每一根骨头:属性。属性(Property)是对象某一方面特征的定义,相当于数据表的一列;属性值是某个对象在这一列上的取值。
除了名字和类型,一个属性还带着一组元数据,让人和智能体读得懂它:
name:API name,camelCase,最多 64 个字符,同一个对象类型里不能重复。title和comment:显示名和说明,写给人看。unit:单位,最多 16 个字符。数值有了单位,读的人就不用猜。synonyms:同义词。智能体靠它按业务说法找到属性,比如把goodQty找成「良品数」。visibility和status:让应用知道这个属性该多显眼、能不能依赖。
元数据写全的属性长这样。它的值大多来自数据源里的一列,也可以只在语义层维护,那是第 7 节的内容。
{ "name": "goodQty", "type": "integer", "title": "Good quantity", "unit": "pcs",
"synonyms": ["yield", "good count"], "comment": "Units that passed final inspection." }
应用和 Action 按 API name 引用属性,所以改类型、删属性都是破坏性改动,要走分支和提案;只改显示名、说明和同义词,不会打断任何引用。
基础类型:一张全表
基础类型(base type)决定属性存什么形状的值,也决定应用能对它做什么。AIDC 支持 string、integer、long、short、byte、boolean、float、double、decimal、date、timestamp、array、struct、vector、geopoint、geoshape、attachment、mediaReference、timeseries、geotimeSeriesReference、cipherText、marking。最常被问的是:哪个类型能做主键,哪个能做标题键?
| 能做标题键吗 | 能做主键吗 | |
|---|---|---|
string、integer、short | 能 | 能 |
date、timestamp | 能 | 不建议,给警告 |
boolean、byte、long | 能 | 不建议,给警告 |
float、double、decimal | 能 | 不能 |
array | 内层类型能做时才能 | 不能 |
geopoint、cipherText | 能 | 不能 |
vector、struct、geoshape、marking | 不能 | 不能 |
attachment、mediaReference、timeseries、geotimeSeriesReference | 不能 | 不能 |
「不能」的,在定义时就会被拒绝;「不建议」的,能保存,但会给一个警告。
这些类型也决定了 Semantic 数据库里的列类型:string、marking、cipherText 是 text;integer、short、byte、long 是 bigint;float、double 是 double precision;decimal 是 numeric;boolean 是 boolean;date、timestamp 分别是 date、timestamptz;其余类型是 jsonb。
给一个属性选类型的四个问题
遇到一个新字段,不用背表,按顺序问四个问题:
- 它是名字还是数?
编号、代码是
string,计数是integer,金额是decimal,测量值和评分是double。 - 只有日期,还是精确到时刻?
承诺交期只要日期,用
date;工单的开始和到期要精确到时刻,用timestamp。 - 一个值,还是多个值?
多个同类值用
array;几个有名字的字段用结构体,后面的课会讲。 - 它要做主键或标题键吗?
回到上面的表查一遍,再决定。
最常见的坑是全部写成 string。ERP 导出的文本里什么都是字符串,照单全收的话,数量没法求和,日期没法比较,排序也会按字母来。类型在定义里选对一次,比在每个应用里各转换一遍划算得多。
选类型时会踩的坑
金额用 decimal
金额和要精确的数量用 decimal。它和 long 读出来都是字符串,例如 "18450.00",先转成数字再相加。
日期和时刻分开
date 只有日期,写成 YYYY-MM-DD,没有时区;timestamp 是精确到时刻的 UTC ISO 8601。promisedDate 是日期,dueAt 是时刻。别拿它们做主键,存储格式和显示格式不同,容易撞。
布尔只有两种
「未检、通过、不通过」是三种状态,别用布尔加空值,用带 enum 约束的 string。布尔做主键的话,整个类型最多只有两个对象。
大整数用字符串
大于 1e15 的 long,在 JavaScript 前端里会丢精度。编号用 string,计数用 integer,long 留给真正需要的场合。
数组要同时写 arraySubType:客户的标签是 array 加 string。数组里不能有 null,不能嵌套,vector 和 timeseries 也不能放进数组。下面是 SalesOrder 的定义和读回来的一个对象,注意 totalUsd 的写法。
{
"kind": "objectType",
"apiName": "SalesOrder",
"title": "Sales order",
"schema": {
"titleColumn": "orderNo",
"columns": [
{ "name": "orderNo", "type": "string", "primaryKey": true, "title": "Order no." },
{ "name": "orderDate", "type": "date", "title": "Order date" },
{ "name": "promisedDate", "type": "date", "title": "Promised date" },
{ "name": "totalUsd", "type": "decimal", "title": "Order total", "unit": "USD" },
{ "name": "customerId", "type": "string", "title": "Customer", "references": { "entity": "Customer", "column": "customerId" } }
]
}
}
{
"__apiName": "SalesOrder",
"__primaryKey": "SO-2026-0412",
"__title": "SO-2026-0412",
"orderNo": "SO-2026-0412",
"orderDate": "2026-09-02",
"promisedDate": "2026-10-15",
"totalUsd": "18450.00",
"customerId": "C-1008"
}
下一节讲那些不是「一个数字或一段文字」的类型:位置、时间序列、向量、附件。
要点
- 基础类型决定值的形状;
string、integer、short能做主键,小数、数组、结构体等不能。 - 标题键的限制比主键松:小数和地理点也行,
vector、struct、时间序列等不行。 - 金额用
decimal;date没有时区,timestamp是 UTC 时刻。 decimal和long读出来是字符串;大于 1e15 的long在前端会丢精度。- 布尔只有两种状态,三种以上用带 enum 约束的
string。
练一练
给「物料」选类型
material 有 materialCode、name、unit、onHandQty、safetyStockQty、leadTimeDays 六个属性。
为六个属性各选一个基础类型,指出主键。ERP 里的库存量有时带小数(按千克计),你会怎么改?
SalesOrder 的三个候选主键:orderDate、totalUsd、orderNo。哪个能做,哪个会被拒绝,哪个会给警告?
在自己的 Semantic 里对一个有小数或长整数属性的对象跑 aidc semantic object,找出哪些值是以字符串形式读回来的。
小测
选一个答案,马上看解析。
Q1SalesOrder.totalUsd 是金额,要精确到分。选哪个类型?
金额要精确,所以用 decimal。double 和 float 是浮点数,有舍入误差。decimal 读出来是字符串,相加前先转换。
Q2把 machine.vibration(timeseries)设成标题键,会怎样?
标题键和主键的限制都在定义时校验。timeseries、vector、struct 等类型两个都不能做。
Q3为什么编号类字段通常用 string,而不用 long?
long 能存能读,但前端的数字装不下太大的整数。编号不用做算术,存成字符串最稳。long 做主键并不会被拒绝,只是给警告。