Eu quero abstrair uma hierarquia do mundo real em um modelo de banco de dados estrito (o mais estrito possível).
Meu problema é criar uma estrutura com um conjunto de regras isso ou isso, mas não os dois.
Eu tenho dois tipos de entidade,
Device , deve ser conectável a outro "dispositivo" como filho e como pai.
Combiner , pode ser conectado a vários "dispositivos" como pais e um como filho.
MAS(!) um dispositivo só pode ser conectado a um deles ao mesmo tempo. Então, como "dispositivo" como apenas um filho e um dos pais.
Eu tento visualizá-lo de alguma forma:
Todas as minhas ideias não são rígidas, mas procuro se existe um padrão para resolver isso sem regras em nível de aplicação. Em um modelo de classe eu resolveria isso com herança. Algumas ideias?
Aqui está uma solução possível. Navegar na estrutura de cima para baixo pode ser um pouco grosseiro, mas talvez os objetos do lado do aplicativo possam lidar com isso.
Eu acho que você pode construir isso usando 2 tabelas
dbo.Device
e arquivosdbo.Combiner
. Cada tabela tem uma coluna que faz referência a quem é seu objeto pai, independentemente de ser umdevice
ou umcombiner
. Podemos então usar alguns tipos diferentesconstraints
e algunstriggers
para garantir que os dados sigam o caminho que você deseja usar.Estruturas de tabela (agora seus objetos provavelmente têm mais pontos de dados do que apenas a,
name
mas por uma questão de simplicidade, vou acompanhar apenas aname
)dbo.Device
dbo.Combiner
Cada tabela contém quem é seu objeto pai via
ParentDeviceID
ouParentCombinerID
. OUnique Filtered Index
onParentDeviceID
ajuda a garantir que um dadoDevice
possa ser apenas o pai de um objeto (AUnique Constraint
pararia várias linhas com umNULL
valor). Não é garantido, então é por isso que vamos usar alguns gatilhos no futuro. Os doisCHECK Constraint
s ajudam a garantir que qualquer objeto possa ter apenas 1 objeto pai em vez de ter aDevice
eCombiner
como pai. OsForeign Key
s garantem que os valores armazenados emParentDeviceID
eParentCombinerID
sejam valores válidos para essas duas tabelas.Trigger
sPodemos inserir um
Trigger
em cadatable
. EstesTrigger
s precisam garantir:insert
/update
de umdbo.Device
registro em que um valor armazenadoParentDeviceID
ainda não está emdbo.Combiner.ParentDeviceID
Insert
/Update
de umdbo.Combiner
registro em que um valor armazenadoParentDeviceID
ainda não está emdbo.Device.ParentDeviceID
Como alternativa, esta pergunta do StackOverflow aparentemente dá o mesmo efeito ou similar com um
Unique Index
em umView
. Se você quiser evitarTriggers
do que isso pode ser uma solução para você. https://stackoverflow.com/questions/16314372/ms-sql-server-cross-table-constraint . Eu não estou familiarizado com essa abordagem, mas talvez seja uma solução melhor para você.Exemplos
A implementação do 1º Exemplo fornecido (apenas 3 dispositivos em uma cadeia) seria algo assim. Apenas 3 registros em
dbo.Device
:A implementação do 2º Exemplo fornecido (1 Device --> 1 Combiner --> 3 Devices) seria algo assim. 4 registros em
dbo.Device
e 1 registro emdbo.Combiner
.Mais um exemplo um pouco mais complicado para exibir todas as opções de relacionamento:
Espero que isso forneça tudo o que você precisa do lado do banco de dados. Novamente, acho que isso será complicado no lado do aplicativo, navegando pelas estruturas da tabela. Mas o banco de dados deve manter os relacionamentos do jeito que você deseja.