Relações e enums
Ligar tabelas umas às outras — cardinalidade, navegadores, relações físicas e virtuais — e fechar o conjunto de valores de um campo com um enum.
Uma tabela sozinha guarda uma lista. Uma aplicação precisa de mais: que os contactos saibam a que conta pertencem, que as oportunidades saibam de quem são, que um campo estado só aceite os estados que existem.
São as duas peças desta página: as relações, que ligam entidades umas às outras, e os enums, que fecham o conjunto de valores possíveis de um campo.
As relações
No diagrama do modelo, cada relação é uma linha entre duas entidades, com uma
etiqueta que diz o nome do caminho e a cardinalidade — na Gestão de Clientes,
conta · 1:N entre Contas e Contactos, e outra igual entre Contas
e Oportunidades.

Uma relação tem sempre dois lados:
- O lado filho (child), que guarda a referência — a coluna
conta_idda tabelacontactos. - O lado pai (parent), que é referenciado — a coluna
idda tabelacontas.
Criar uma relação
As relações desenham-se no diagrama, ligando um campo a outro:
- Passa o rato sobre o campo do lado filho — a linha responde com a dica Arrasta para um campo de outra tabela para ligar.
- Arrasta desse campo até ao campo do lado pai (tipicamente a chave primária da outra entidade) e larga.
- Abre-se o diálogo Nova relação, já com as duas entidades e as duas colunas preenchidas — vieram do arrasto e não se editam ali.
- Preenche o resto (a seguir) e confirma com Criar relação.
A cardinalidade
O primeiro campo do diálogo é a Cardinalidade — quantos de cada lado:
| Opção | Quando se usa |
|---|---|
| One-to-many (1:N) | Uma conta tem vários contactos. É o caso mais comum. |
| Many-to-one (N:1) | O mesmo, visto do outro lado. |
| One-to-one (1:1) | Um registo para um registo — uma conta e a sua ficha fiscal. |
| Many-to-many (N:N) | Muitos para muitos — etiquetas em contas, formadores em cursos. Precisa de uma tabela de junção. |
Conforme a escolha, o diálogo mostra Child (tem a FK) e Parent (referenciada) — ou, no caso N:N, Entidade A e Entidade B.
Os navegadores
Os dois campos seguintes são os navegadores — o coração da relação, e o que a torna útil fora do diagrama.
Um navegador é um campo virtual que não existe na base de dados: serve para saltar de um registo para os registos relacionados e para trazer as colunas do outro lado nas APIs. São eles que fazem uma consulta de contactos devolver, junto com cada contacto, o nome da conta a que pertence — sem segunda consulta e sem código.
- Navigator em Contactos → Contas — o caminho do filho para o pai. Um
nome no singular:
conta. - Navigator em Contas → [Contactos] — o caminho do pai para os filhos. Um
nome no plural:
contactos. Os parêntesis rectos no rótulo dizem que este lado devolve uma lista.
Deixar um dos campos vazio é uma decisão legítima: esse lado simplesmente não é exposto. Se ninguém precisa de ir de uma conta para os seus contactos, não crias o caminho.
No cartão da entidade, os navegadores aparecem na secção Navegação, com o nome à esquerda e o destino à direita — entre parêntesis rectos quando é uma lista.

Dica
Trata os nomes dos navegadores como parte da linguagem da app: conta,
contactos, linhas, responsavel. São eles que vais ler nas APIs, nos
datastores dos ecrãs e no código dos eventos — e um fk_ct_2 mal escolhido
hoje é confusão para sempre.
Física ou virtual
O campo Tipo de relação decide se a relação também é escrita na base de dados:
| Opção | O que faz |
|---|---|
| Virtual — só no modelo da plataforma | A relação existe para a plataforma: navegadores, APIs, ecrãs. A base de dados não é tocada. |
| Física — cria a FK na base de dados | Além do modelo, é criada a chave estrangeira no motor: passa a ser o próprio motor a recusar um conta_id que não exista. |
A relação física é mais segura — a integridade deixa de depender de quem escreve. A virtual é o que sobra quando não se pode (ou não se quer) mexer no esquema da base de dados: bases de dados de terceiros, tabelas partilhadas com outros sistemas, dados históricos que não passariam na verificação.
Ao apagar o pai
Ao apagar o pai (ON DELETE) diz o que acontece aos filhos quando o registo pai é apagado:
| Opção | O que acontece |
|---|---|
| Nada (bloqueia se houver filhos) | A eliminação falha enquanto houver filhos. |
| Restrict — bloqueia imediatamente | O mesmo, verificado logo. |
| Cascade — apaga os filhos | Apagar a conta apaga os contactos e as oportunidades dela. |
| Set NULL — solta os filhos | Os filhos ficam sem pai (a coluna passa a vazia). Exige que a coluna aceite vazio. |
Numa relação física, esta regra é aplicada pelo motor. Numa relação virtual, fica guardada no modelo e passa a valer se um dia a relação for materializada.
Atenção
Cascade é conveniente e é irreversível: apagar uma conta leva contactos, oportunidades e tudo o que estiver pendurado. Em dados de negócio, o costume é preferir Nada e tratar a eliminação como um processo — só apaga quem já não tem nada dependente.
Muitos-para-muitos
Com Many-to-many (N:N) o diálogo pede mais três coisas, porque uma relação destas precisa de uma tabela pelo meio (a tabela de junção), com uma referência para cada lado:
| Campo | O que é |
|---|---|
| Tabela de junção | A tabela que liga as duas — por exemplo conta_etiqueta. |
| Coluna → A (child) | A coluna da junção que aponta para a primeira entidade. |
| Coluna → B (parent) | A coluna da junção que aponta para a segunda. |
A tabela de junção tem de existir antes: cria-a como qualquer outra (ver Tabelas e campos).
Relações que já vêm feitas
Ao importar uma tabela para o modelo, as chaves estrangeiras que já existirem na base de dados entram sozinhas como relações, com navegadores propostos a partir dos nomes das tabelas. Foi assim que a Gestão de Clientes nasceu com as suas duas relações — só é preciso confirmar se os nomes dos navegadores são os que queres ler no resto da app.
Remover uma relação
Clica na linha da relação no diagrama e confirma. A pergunta é explícita: Remover esta relação do modelo? — e a resposta também: a relação sai do modelo da plataforma e uma FK física já criada na base de dados NÃO é removida. Se querias mesmo desfazer a chave estrangeira no motor, isso faz-se na base de dados.
Para que servem, depois
Feita a relação, ela aparece em todo o lado:
- Nas APIs, como campos aninhados: uma consulta de contactos pode
devolver
conta { nome, cidade }. - Nos datastores dos ecrãs, para montar mestre-detalhe — a tabela de
contactos filtrada pelo
idda conta carregada (ver Datastores e dados). - Na integridade dos dados, quando a relação é física.
Os enums
Um enum é um conjunto fechado de valores para um campo: o estado de uma
conta é Activa, Suspensa ou Perdida, e mais nada. Em vez de deixar o
campo aceitar texto livre — e acabar com "activa", "Activa", "ACTIVA" e
"activo" na mesma coluna — declara-se o conjunto uma vez.
Criar um enum
O enum nasce na coluna, no momento em que lhe dás o tipo:
- No diálogo Nova tabela (ou em Editar estrutura), selecciona a coluna.
- Em Tipo, escolhe
enum. - Aparece a caixa Itens do enum. Clica em Adicionar item para cada valor.
- Preenche as três colunas de cada item:
| Coluna | O que é |
|---|---|
| Valor | O valor guardado. Letras, dígitos e _, a começar por letra — por convenção em maiúsculas: ATIVO, EM_ANALISE. |
| Label | O texto que as pessoas vêem: Activo, Em análise. |
| Cor | Uma cor opcional, usada pelos widgets que pintam estados (o Kanban, as regras de formatação). |

Cada coluna enumerada tem o seu enum, e o nome dele é derivado da tabela e
da coluna — a coluna tipo da tabela actividades dá o enum
ActividadesTipo.
Nota
Na base de dados, uma coluna enum é guardada num campo estruturado — a própria caixa avisa: Na BD fica um campo JSON (1 ou N valores). É isso que deixa o mesmo campo servir para uma escolha única hoje e para múltipla escolha amanhã, sem mudar o esquema.
Alterar um enum
Reabre Editar estrutura na tabela, selecciona a coluna e mexe nos Itens do enum: acrescentar, mudar a etiqueta, mudar a cor, remover com o ×. Confirma com Aplicar alterações.
Mudar a etiqueta ou a cor é seguro — são só apresentação. Mudar ou remover um valor não é: os registos que já tinham o valor antigo ficam com um valor que o enum já não conhece.

Onde os enums aparecem
Um campo enumerado deixa de ser texto livre em toda a plataforma:
| Onde | O que muda |
|---|---|
| No diagrama | O campo aparece em itálico, com o nome do enum no lugar do tipo. |
| Nas APIs | O campo fica com um tipo de valores fixos, e a API recusa qualquer valor de fora da lista. |
| No widget Lista | Em Origem das opções, escolhe-se Enum do modelo e depois o Campo enum — as opções e as etiquetas vêm do modelo, e não há listas para manter em dois sítios. |
| No Kanban | Em Fonte das colunas, a opção Enum cria uma coluna por valor do enum, já com as cores. |
| Nas regras de formatação | As condições comparam com os valores do enum. |
Dica
Sempre que um campo tem um conjunto conhecido de valores — estado, tipo, prioridade, canal — faz dele um enum em vez de uma caixa de texto. Ganhas as etiquetas traduzíveis, as cores, os filtros certos e um Kanban de graça.
Porque não…?
- Porque não consigo arrastar de um campo para o outro? O arrasto começa na linha do campo do lado filho e acaba na linha do campo do lado pai. Se estás a arrastar o cartão inteiro, estás a movê-lo no diagrama — pega na linha do campo.
- Porque é que a API não devolve os dados da tabela relacionada? Falta o navegador desse lado. Um navegador vazio é um lado que não foi exposto de propósito — cria a relação de novo com o nome preenchido.
- Porque falhou a criação da relação física? Uma chave estrangeira só é aceite se os dados já existentes a respeitarem. Se houver filhos a apontar para pais que não existem, o motor recusa — limpa os órfãos primeiro, ou cria a relação como virtual.
- Porque continuo a ver a relação depois de a remover? Removeste-a do modelo; a chave estrangeira na base de dados continua lá e é ela que a reimportação volta a trazer.
- Porque é que o meu campo enum mostra o valor em vez da etiqueta? O widget não está ligado ao enum do modelo — em vez de uma lista fixa, escolhe Enum do modelo e aponta o Campo enum.