---
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>
</CardGroup>

## 实体一览

| 实体     | 目的                                                    | 定义方式                                        |
| ------ | ----------------------------------------------------- | ------------------------------------------- |
| **对象** | 具有自有字段的新自定义记录类型（例如 PostCard、Invoice）                  | `defineObject()`                            |
| **字段** | 对象上的一列。 独立字段可以扩展你未创建的对象（例如向 Company 添加 `loyaltyTier`） | `defineField()`                             |
| **关系** | 两个对象之间的双向链接——双方都声明为字段                                 | 使用 `defineField()` 并指定 `FieldType.RELATION` |
| **索引** | 用于加速在某个对象上经常执行的查询的数据库索引                               | `defineIndex()`                             |

SDK 会在构建时通过 AST 分析检测这些内容，因此文件组织方式由你决定——约定是使用 `src/objects/`、`src/fields/` 和 `src/indexes/`。 稳定的 `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>
