数据库设计 - 多个表的外键

时间:2018-04-18 12:26:11

标签: sql-server relational-database

我有以下表格

CREATE TABLE [dbo].[User]
(
    [Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
    [Username] NVARCHAR(200) NOT NULL,
    [Domain] NVARCHAR(200) NOT NULL,
    [IsAdministrator] BIT NOT NULL DEFAULT 'false',
    [IsGroup] BIT NULL DEFAULT 'false', 
)

CREATE TABLE [dbo].[Role]
(
    [Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY, 
    [Name] NVARCHAR(500) NOT NULL, 
    [Description] NVARCHAR(1000) NOT NULL, 
    [ResourceType] NVARCHAR(100) NOT NULL,
)

可以为用户分配特定资源的一个或多个角色

例如, 假设有两种类型的资源(WorkspaceProcess

每种资源类型都有一个表,每种资源的模式都不同(因此我不能使用通用资源表)

CREATE TABLE [dbo].[Workspace]
(
    [WorkspaceId] UNIQUEIDENTIFIER NOT NULL, 
    [WorkspaceName] NVARCHAR(100) NOT NULL,
    [Description] NVARCHAR(500) NULL,

    CONSTRAINT [UC_WorkspaceName] UNIQUE([WorkspaceName]),
    CONSTRAINT [PK_Workspace] PRIMARY KEY([WorkspaceId])
)

CREATE TABLE [dbo].[Process]
(
    [ProcessId] UNIQUEIDENTIFIER NOT NULL , 
    [ProcessName] NVARCHAR(100) NOT NULL,

    CONSTRAINT [PK_BusinessProcessId] PRIMARY KEY ([ProcessId]), 
)

但无论资源类型如何,主键始终为UNIQUEIDENTIFIER

每个用户可以为特定的ResourceId和ResourceType

分配一个或多个角色
CREATE TABLE [dbo].[UserRole]
(
    [UserId] UNIQUEIDENTIFIER NOT NULL,
    [RoleId] UNIQUEIDENTIFIER NOT NULL,
    [ResourceType] NVARCHAR(100) NOT NULL,
    [ResourceId] UNIQUEIDENTIFIER NOT NULL,

    CONSTRAINT [PK_User_Role] PRIMARY KEY (ResourceId, UserId, RoleId, ResourceType),
    CONSTRAINT [FK_UserId] FOREIGN KEY ([UserId]) REFERENCES [User]([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [Role]([Id]) ON DELETE CASCADE
)

但是使用此设计,我无法将UserRole.ResourceId设置为外键,因为它可能来自WorkspaceIdWorkspace或来自{ProcessId Process 1}}表。

这在资源删除期间成为一个问题,因为我必须手动删除过时的条目。

我知道我可以在UserRole中有两列名为WorkspaceIdProcessId,根据资源类型设置NULL,但在我的情况下,资源类型的数量将会非常大。

我的问题是,

还有其他方法我不必为每种新资源类型添加一列,还是应该使用当前设计(没有外键)?

1 个答案:

答案 0 :(得分:0)

我将工作空间和流程组合到一个表中,并将它们链接到ResourceType表。

CREATE TABLE [dbo].[User]
(
    [Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
    [Username] NVARCHAR(200) NOT NULL,
    [Domain] NVARCHAR(200) NOT NULL,
    [IsAdministrator] BIT NOT NULL DEFAULT 'false',
    [IsGroup] BIT NULL DEFAULT 'false', 
)

CREATE TABLE [dbo].[ResourceType]
(
    [Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
    [Description] NVARCHAR(100)
)

CREATE TABLE [dbo].[Role]
(
    [Id] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY, 
    [Name] NVARCHAR(500) NOT NULL, 
    [Description] NVARCHAR(1000) NOT NULL, 
    [ResourceType_id] UNIQUEIDENTIFIER NOT NULL
)

CREATE TABLE [dbo].[Resource]
(
    [ResourceId] UNIQUEIDENTIFIER NOT NULL, 
    [ResourceName] NVARCHAR(100) NOT NULL,
    [Description] NVARCHAR(500) NULL,
    [ResourceType_id] UNIQUEIDENTIFIER NOT NULL,

    CONSTRAINT [UC_ResourceName] UNIQUE([ResourceName]),
    CONSTRAINT [PK_Resource] PRIMARY KEY([ResourceId])
)

CREATE TABLE [dbo].[UserRole]
(
    [UserId] UNIQUEIDENTIFIER NOT NULL,
    [RoleId] UNIQUEIDENTIFIER NOT NULL,
    [ResourceType] NVARCHAR(100) NOT NULL,
    [ResourceId] UNIQUEIDENTIFIER NOT NULL,

    CONSTRAINT [PK_User_Role] PRIMARY KEY (ResourceId, UserId, RoleId, ResourceType),
    CONSTRAINT [FK_UserId] FOREIGN KEY ([UserId]) REFERENCES [User]([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [Role]([Id]) ON DELETE CASCADE,
    CONSTRAINT [FK_ResourceId] FOREIGN KEY ([ResourceId]) REFERENCES [Resource]([ResourceId]) ON DELETE CASCADE
)