最近,我负责清理SQL Server 2008数据库和网站代码,并且无法提出解决以下问题的优雅解决方案。在网站上,有些用户具有不同的角色,每个角色都有许多权限。网站上的管理员可以启用或禁用给定角色的权限。
目前,数据库未规范化,表格设置如下:
角色:
RoleID | RoleName | Permissions
1 | Admin | 1;2;3;4;5;etc.
2 | User | 4;23;54;etc.
3 | Person | 54;2;3;45;etc.
权限:
PermissionID | PermissionName
1 | Random Name
2 | You get the idea
3 | etc.
要更新角色权限,它们基本上遍历代码隐藏中的每个复选框,生成“权限字符串”并在单个调用中更新行。
我想按如下方式规范化数据库:
角色:
RoleID | RoleName
1 | Admin
2 | User
3 | Person
权限:
PermissionID | PermissionName
1 | Random Name
2 | You get the idea
3 | etc.
RolePermissions:
rpID | RoleID | PermissionID
1 | 1 | 1
2 | 1 | 2
3 | 1 | 20
4 | 2 | 5
5 | 2 | 2
问题是用户可能希望一次更改20-30个权限。我能想到的唯一方法是删除该角色的每个权限,然后逐个添加每个角色权限关系。通常情况下这不是问题,但我们的数据库存储在与我们的代码不同的服务器上,因此单独制作30多个命令中的每一个的网络延迟将是一个杀手。我也知道在这种情况下,用户应该很少更新角色,但我试图将整个数据库切换为规范化,因此在更常用的页面上的其他地方会出现此问题。
我想知道在一个或两个SQL命令中是否有一种优雅的方式将新的Role-Permission关系插入RolePermissions表(如果它们不存在),并删除任何不再存在的RolePermissions。这背后的代码是C#,因此我可以非常轻松地生成所需的任何SQL命令字符串。有什么建议吗?
如果需要更多信息,我会提供。
答案 0 :(得分:1)
如果您使用的是最近支持表值参数的客户端库,则可以使用它们将数据列表发送到存储过程。
create type PermissionList as table (
PermissionID int not null
);
Go
create proc UpdateRolePermissions
@roleID int,
@permissionList PermissionList readonly
as
with t as (
select
*
from
dbo.RolePermissions
where
RoleId = @roleID
)
merge
t
using
@permissionList s
on
t.PermissionID = s.PermissionID
when not matched by source then
delete
when not matched by target then
insert (roleID, permissionID)
values (@roleID, s.PermissionID)
;
go
如果有更多数据且您需要在匹配时更新某些内容,您还可以添加when matched then update
子句
Example of using table valued parameter from C#
<强> Example SQLFiddle 强>