É aceitável ter uma referência circular entre duas tabelas no campo de chave estrangeira?
Se não, como essas situações podem ser evitadas?
Se sim, como os dados podem ser inseridos?
Abaixo está um exemplo de onde (na minha opinião) uma referência circular seria aceitável:
CREATE TABLE Account
(
ID INT PRIMARY KEY IDENTITY,
Name VARCHAR(50)
)
CREATE TABLE Contact
(
ID INT PRIMARY KEY IDENTITY,
Name VARCHAR(50),
AccountID INT FOREIGN KEY REFERENCES Account(ID)
)
ALTER TABLE Account ADD PrimaryContactID INT FOREIGN KEY REFERENCES Contact(ID)
Como você está usando campos anuláveis para as chaves estrangeiras, você pode, de fato, construir um sistema que funcione corretamente da maneira que você imagina. Para inserir linhas na tabela Contas, você precisa ter uma linha presente na tabela Contatos, a menos que permita inserções em Contas com um PrimaryContactID nulo. Para criar uma linha de contato sem já ter uma linha Account presente, você deve permitir que a coluna AccountID na tabela Contacts seja anulável. Isso permite que as contas não tenham contatos e permite que os contatos não tenham conta. Talvez isso seja desejável, talvez não.
Dito isto, minha preferência pessoal seria ter a seguinte configuração:
Isso fornece a capacidade de:
IX_AccountsContactsXRef_Primary
índice. Este índice contém um filtro, por isso só funcionará em plataformas que os suportam. Como esse índice é especificado com aUNIQUE
opção, só pode haver um único contato principal para cada conta.Por exemplo, se você deseja exibir uma lista de todos os contatos, com uma coluna indicando o status "principal", mostrando os contatos principais no topo da lista de cada conta, você pode fazer:
O índice filtrado evita a inserção de mais de um único contato principal por conta, ao mesmo tempo em que fornece um método rápido de retornar uma lista de contatos principais. Pode-se facilmente imaginar outra coluna,
IsActive
com um índice filtrado não exclusivo para manter um histórico de contatos por conta, mesmo depois que esse contato não estiver mais associado à conta:Não, não é aceitável ter referências circulares de chave estrangeira. Não apenas porque seria impossível inserir dados sem descartar e recriar constantemente a restrição. mas porque é um modelo fundamentalmente falho de todo e qualquer domínio que eu possa imaginar. No seu exemplo, não consigo pensar em nenhum domínio em que o relacionamento entre Conta e Contato não seja NN, exigindo uma tabela de junção com referências FK de volta para Conta e Contato.
Você pode fazer com que seu objeto externo aponte para o contato principal, e não para a conta. Seus dados ficariam assim: