Vai al contenuto principale
Le relazioni collegano due oggetti tra loro. In Twenty, le relazioni sono sempre bidirezionali — ogni relazione ha due lati e ciascun lato è dichiarato come un campo che fa riferimento all’altro.
Tipo di relazioneDescrizioneHa una chiave esterna?
MANY_TO_ONEMolti record di questo oggetto puntano a un record della destinazioneSì (joinColumnName)
ONE_TO_MANYUn record di questo oggetto ha molti record della destinazioneNo (lato inverso)

Come funzionano le relazioni

Ogni relazione richiede due campi che fanno riferimento l’uno all’altro:
  1. Il lato MANY_TO_ONE — risiede sull’oggetto che detiene la chiave esterna.
  2. Il lato ONE_TO_MANY — risiede sull’oggetto che possiede la collezione.
Entrambi i campi usano FieldType.RELATION e si riferiscono reciprocamente tramite relationTargetFieldMetadataUniversalIdentifier.

Esempio: Post Card ha molti destinatari

Un PostCard può essere inviato a molti record PostCardRecipient. Ogni destinatario appartiene esattamente a una sola cartolina. Passaggio 1: definisci il lato ONE_TO_MANY su PostCard (il lato “uno”):
src/fields/post-card-recipients-on-post-card.field.ts
import { defineField, FieldType, RelationType } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';

// Export so the other side can reference it
export const POST_CARD_RECIPIENTS_FIELD_ID = 'a1111111-1111-1111-1111-111111111111';
// Import from the other side
import { POST_CARD_FIELD_ID } from './post-card-on-post-card-recipient.field';

export default defineField({
  universalIdentifier: POST_CARD_RECIPIENTS_FIELD_ID,
  objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
  type: FieldType.RELATION,
  name: 'postCardRecipients',
  label: 'Post Card Recipients',
  icon: 'IconUsers',
  relationTargetObjectMetadataUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
  relationTargetFieldMetadataUniversalIdentifier: POST_CARD_FIELD_ID,
  universalSettings: {
    relationType: RelationType.ONE_TO_MANY,
  },
});
Passaggio 2: definisci il lato MANY_TO_ONE su PostCardRecipient (il lato “molti” — contiene la chiave esterna):
src/fields/post-card-on-post-card-recipient.field.ts
import { defineField, FieldType, RelationType, OnDeleteAction } from 'twenty-sdk/define';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';

// Export so the other side can reference it
export const POST_CARD_FIELD_ID = 'b2222222-2222-2222-2222-222222222222';
// Import from the other side
import { POST_CARD_RECIPIENTS_FIELD_ID } from './post-card-recipients-on-post-card.field';

export default defineField({
  universalIdentifier: POST_CARD_FIELD_ID,
  objectUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
  type: FieldType.RELATION,
  name: 'postCard',
  label: 'Post Card',
  icon: 'IconMail',
  relationTargetObjectMetadataUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
  relationTargetFieldMetadataUniversalIdentifier: POST_CARD_RECIPIENTS_FIELD_ID,
  universalSettings: {
    relationType: RelationType.MANY_TO_ONE,
    onDelete: OnDeleteAction.CASCADE,
    joinColumnName: 'postCardId',
  },
});
Importazioni circolari: entrambi i campi di relazione fanno riferimento all’universalIdentifier dell’altro. Per evitare problemi di importazioni circolari, esporta gli ID dei campi come costanti denominate da ciascun file e importale nell’altro. Il sistema di build le risolve in fase di compilazione.

Relazioni con gli oggetti standard

Per creare una relazione con un oggetto Twenty integrato (Person, Company, ecc.), usa STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS:
src/fields/person-on-self-hosting-user.field.ts
import {
  defineField,
  FieldType,
  RelationType,
  OnDeleteAction,
  STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
import { SELF_HOSTING_USER_UNIVERSAL_IDENTIFIER } from '../objects/self-hosting-user.object';

export const PERSON_FIELD_ID = 'c3333333-3333-3333-3333-333333333333';
export const SELF_HOSTING_USER_REVERSE_FIELD_ID = 'd4444444-4444-4444-4444-444444444444';

export default defineField({
  universalIdentifier: PERSON_FIELD_ID,
  objectUniversalIdentifier: SELF_HOSTING_USER_UNIVERSAL_IDENTIFIER,
  type: FieldType.RELATION,
  name: 'person',
  label: 'Person',
  description: 'Person matching with the self hosting user',
  isNullable: true,
  relationTargetObjectMetadataUniversalIdentifier:
    STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.universalIdentifier,
  relationTargetFieldMetadataUniversalIdentifier: SELF_HOSTING_USER_REVERSE_FIELD_ID,
  universalSettings: {
    relationType: RelationType.MANY_TO_ONE,
    onDelete: OnDeleteAction.SET_NULL,
    joinColumnName: 'personId',
  },
});

Proprietà dei campi di relazione

ProprietàObbligatorioDescrizione
typeDeve essere FieldType.RELATION
relationTargetObjectMetadataUniversalIdentifierL’universalIdentifier dell’oggetto di destinazione
relationTargetFieldMetadataUniversalIdentifierL’universalIdentifier del campo corrispondente sull’oggetto di destinazione
universalSettings.relationTypeRelationType.MANY_TO_ONE o RelationType.ONE_TO_MANY
universalSettings.onDeleteSolo MANY_TO_ONECosa accade quando il record referenziato viene eliminato: CASCADE, SET_NULL, RESTRICT o NO_ACTION
universalSettings.joinColumnNameSolo MANY_TO_ONENome della colonna del database per la chiave esterna (ad es., postCardId)

Campi di relazione inline

Puoi anche dichiarare una relazione direttamente all’interno di defineObject. Quando è inline, ometti objectUniversalIdentifier — viene ereditato dall’oggetto padre:
export default defineObject({
  universalIdentifier: '...',
  nameSingular: 'postCardRecipient',
  // ...
  fields: [
    {
      universalIdentifier: POST_CARD_FIELD_ID,
      type: FieldType.RELATION,
      name: 'postCard',
      label: 'Post Card',
      relationTargetObjectMetadataUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
      relationTargetFieldMetadataUniversalIdentifier: POST_CARD_RECIPIENTS_FIELD_ID,
      universalSettings: {
        relationType: RelationType.MANY_TO_ONE,
        onDelete: OnDeleteAction.CASCADE,
        joinColumnName: 'postCardId',
      },
    },
    // … other fields
  ],
});