Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
102 lines
5.6 KiB
Plaintext
102 lines
5.6 KiB
Plaintext
---
|
||
title: 概览
|
||
description: 定义你的应用在工作区中添加的数据结构——对象、字段和关系。
|
||
icon: database
|
||
---
|
||
|
||
Twenty 应用的 **数据层(data layer)** 是你的应用*添加*到工作区中的数据——它声明的新记录类型、它为现有对象添加的列,以及这些记录之间如何相互关联。
|
||
|
||
```text
|
||
┌──────────────────────────────────────────────────┐
|
||
│ Object — a record type, e.g. PostCard │
|
||
│ ├─ Field (name, type, label) │
|
||
│ ├─ Field │
|
||
│ └─ Relation (link to another object) │
|
||
└──────────────────────────────────────────────────┘
|
||
│
|
||
├── lives in your app, OR
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────┐
|
||
│ Standard / other apps' objects │
|
||
│ └─ Field added by your app via defineField │
|
||
└──────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 本节内容
|
||
|
||
<CardGroup cols={2}>
|
||
<Card title="对象" icon="table" href="/l/zh/developers/extend/apps/data/objects">
|
||
`defineObject` —— 声明具有自有字段的新记录类型。
|
||
</Card>
|
||
<Card title="扩展对象" icon="wand-magic-sparkles" href="/l/zh/developers/extend/apps/data/extending-objects">
|
||
`defineField` —— 向标准对象或其他应用的对象添加字段。
|
||
</Card>
|
||
<Card title="关系" icon="diagram-project" href="/l/zh/developers/extend/apps/data/relations">
|
||
对象之间的双向 `MANY_TO_ONE` / `ONE_TO_MANY` 连接。
|
||
</Card>
|
||
<Card title="时间线活动类型" icon="clock-rotate-left" href="/l/zh/developers/extend/apps/data/timeline-activity-types">
|
||
为记录时间线定义自动审计事件和显式应用事件。
|
||
</Card>
|
||
</CardGroup>
|
||
|
||
## 实体一览
|
||
|
||
| 实体 | 目的 | 定义方式 |
|
||
| ----------- | ----------------------------------------------------- | ------------------------------------------- |
|
||
| **对象** | 具有自有字段的新自定义记录类型(例如 PostCard、Invoice) | `defineObject()` |
|
||
| **字段** | 对象上的一列。 独立字段可以扩展你未创建的对象(例如向 Company 添加 `loyaltyTier`) | `defineField()` |
|
||
| **关系** | 两个对象之间的双向链接——双方都声明为字段 | 使用 `defineField()` 并指定 `FieldType.RELATION` |
|
||
| **索引** | 用于加速在某个对象上经常执行的查询的数据库索引 | `defineIndex()` |
|
||
| **时间线活动类型** | 显示在记录时间线中的自动审计事件或显式域事件 | `defineTimelineActivityType()` |
|
||
|
||
SDK 会在构建时通过 AST 分析检测这些内容,因此文件组织方式由你决定——约定是使用 `src/objects/`、`src/fields/`、`src/indexes/` 和 `src/timeline-activity-types/`。 稳定的 `universalIdentifier` UUID 在不同部署之间将一切关联在一起。
|
||
|
||
## 索引(可选)
|
||
|
||
应用可以随对象一同提供索引,以确保经常执行的查询保持快速。 最常见的情况是某个你经常读取的状态列或外键列。
|
||
|
||
```ts src/indexes/post-card-status.index.ts
|
||
import { defineIndex } from 'twenty-sdk/define';
|
||
|
||
import {
|
||
POST_CARD_UNIVERSAL_IDENTIFIER,
|
||
STATUS_FIELD_UNIVERSAL_IDENTIFIER,
|
||
} from '../objects/post-card.object';
|
||
|
||
export default defineIndex({
|
||
universalIdentifier: 'b6e9d2a1-5a4c-46ca-9d52-42c8f02d1ff0',
|
||
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
|
||
fields: [
|
||
{
|
||
universalIdentifier: 'b6e9d2a1-5a4c-46ca-9d52-42c8f02d1ff1',
|
||
fieldUniversalIdentifier: STATUS_FIELD_UNIVERSAL_IDENTIFIER,
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
### 唯一索引
|
||
|
||
`defineIndex` 接受 `isUnique: true`,可同时用于单列和多列表达唯一性约束。 这是推荐的基础方式——`defineField({ isUnique: true })` 已被弃用,并将在未来的版本中移除。
|
||
|
||
```ts
|
||
defineIndex({
|
||
universalIdentifier: '…',
|
||
objectUniversalIdentifier: PERSON_UNIVERSAL_IDENTIFIER,
|
||
isUnique: true,
|
||
fields: [{ universalIdentifier: '…', fieldUniversalIdentifier: EMAIL_FIELD_UNIVERSAL_IDENTIFIER }],
|
||
});
|
||
```
|
||
|
||
### 其他约束
|
||
|
||
* 部分 `WHERE` 子句由管理员控制——应用无法声明它们。
|
||
* 每个对象最多只能有 10 个自定义索引(框架自身的索引不计入其中)。
|
||
|
||
按照 Postgres 使用索引的方式来排列 `fields` 数组——最左边的列放在最前面,就像电话簿一样。 索引不是免费的:对表的每一次写入都会更新索引。 只有当你确实有查询需要某个索引时才添加它。
|
||
|
||
<Note>
|
||
在找 **Application Config** 或 **Roles & Permissions** 吗? 这些描述的是应用本身而不是它添加的数据——相关内容位于 [Config](/l/zh/developers/extend/apps/config/overview) 下。 在找 **Connections**(Linear、GitHub、Slack OAuth)吗? 这些用于*从*逻辑函数中调用,并位于 [Logic](/l/zh/developers/extend/apps/logic/connections) 下。
|
||
</Note>
|