TableA
, TableB
and TableC
all require a single row from TableX
but a row of TableX
cannot be shared between more than one row from tables A-C. (Tables A-C are completely different).
I can think of a few solutions for this, but which one (if any) is correct?
Option 1
Flatten the fields on TableX onto Tables A-C (my least preferable option).
Option 2
This essentially seems like a many-to-one link, but easiest to enforce in the database as a one-to-one. Doesn't work so well with entity framework.
Tables A-C
[Id] IDENTITY INT NOT NULL,
[TableAId] INT NULL,
[TableBId] INT NULL,
[TableCId] INT NULL,
CONSTRAINT [PK_TableX] PRIMARY KEY,
CONSTRAINT [FK_TableX_TableA] FOREIGN KEY [TableAId] REFERENCES [TableA]([Id]),
CONSTRAINT [FK_TableX_TableB] FOREIGN KEY [TableBId] REFERENCES [TableB]([Id]),
CONSTRAINT [FK_TableX_TableC] FOREIGN KEY [TableCId] REFERENCES [TableC]([Id]),
CONSTRAINT [UQ_TableX_TableAId] UNIQUE ([TableAId]),
CONSTRAINT [UQ_TableX_TableBId] UNIQUE ([TableBId]),
CONSTRAINT [UQ_TableX_TableCId] UNIQUE ([TableCId]),
CONSTRAINT [CK_TableX_Owner] CHECK
(
([TableAId] IS NOT NULL AND [TableBId] IS NULL AND [TableCId] IS NULL) OR
([TableBId] IS NOT NULL AND [TableCId] IS NULL AND [TableAId] IS NULL) OR
([TableCId] IS NOT NULL AND [TableAId] IS NULL AND [TableBId] IS NULL)
)
TableX
[Id] IDENTITY INT NOT NULL
Option 3
This is my favoured option as it seems to represent the one-to-one link the best (as we can't have the Id
of TableX
match the primary keys of tables A-C. The ORM (in this case Entity Framework) would handle the rest.
Tables A-C
[Id] IDENTITY INT NOT NULL,
[TableXId] INT NOT NULL,
CONSTRAINT [PK_Table*] PRIMARY KEY,
CONSTRAINT [FK_Table*_TableX] FOREIGN KEY [TableXId] REFERENCES [TableX]([Id]) ON DELETE CASCADE
CONSTRAINT [UQ_Table*_TableXId] UNIQUE ([TableXId])
TableX
Id IDENTITY INT NOT NULL,
CONSTRAINT [PK_TableX] PRIMARY KEY