从文档中:
- 尽管有权访问数据库的任何用户都可以创建图,但是一旦创建了图,唯一可以看到该图的用户就是图的创建者和db_owner角色的任何成员。
- 图的所有权只能转让给db_owner角色的成员。仅当该图的先前所有者已从数据库中删除时,才有可能。
- 如果已将图的所有者从数据库中删除,则该图将保留在数据库中,直到db_owner角色的成员尝试打开它为止。那时,db_owner成员可以选择接管该图的所有权。
因此,您似乎无法使用较低的角色来做到这一点db_datareader
。
在幕后,这是Management Studio调用以驱动列表的内容:
CREATE PROCEDURE dbo.sp_helpdiagrams
(
@diagramname sysname = NULL,
@owner_id int = NULL
)
WITH EXECUTE AS N'dbo'
AS
BEGIN
DECLARE @user sysname
DECLARE @dboLogin bit
EXECUTE AS CALLER;
SET @user = USER_NAME();
SET @dboLogin = CONVERT(bit,IS_MEMBER('db_owner'));
REVERT;
SELECT
[Database] = DB_NAME(),
[Name] = name,
[ID] = diagram_id,
[Owner] = USER_NAME(principal_id),
[OwnerID] = principal_id
FROM
sysdiagrams
WHERE
(@dboLogin = 1 OR USER_NAME(principal_id) = @user) AND
(@diagramname IS NULL OR name = @diagramname) AND
(@owner_id IS NULL OR principal_id = @owner_id)
ORDER BY
4, 5, 1
END
因此,您可以看到与此匹配的文档。
现在有两个解决方法:
- 在登录触发器,更新
principal_id
的所有图表是当前登录。这意味着在下一个用户登录之前,他们将有权访问所有图表。这不是最佳选择。
- 使用触发器在
sysdiagrams
表本身(它不是真正的系统表),并且每当创建或更新图表,添加/更新每个主副本(标有自己的用户名)。两者都不是最佳选择,您可能会让人们整天覆盖彼此的图表。
这是第二种解决方法的想法-您真正需要维护的是想要访问图的数据库主体的列表(您还希望有一些清理已删除图的内容) ,以及一些定期维护,这些维护会删除已删除的主体的图):
CREATE TRIGGER dbo.sysdiagrams_distribute
ON dbo.sysdiagrams
WITH EXECUTE AS N'dbo'
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @p TABLE(principal_id INT, name SYSNAME);
INSERT @p SELECT principal_id, name
FROM sys.database_principals
-- change this list:
WHERE name IN (N'test_blat_user', N'test_blat_user2', N'dbo');
UPDATE d
SET [version] = i.version, definition = i.definition
FROM inserted AS i
CROSS JOIN @p AS p
INNER JOIN dbo.sysdiagrams AS d
ON d.name = i.name
AND d.principal_id = p.principal_id;
INSERT dbo.sysdiagrams(name, principal_id, version, definition)
SELECT i.name, p.principal_id, i.version, i.definition
FROM inserted AS i
CROSS JOIN @p AS p
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.sysdiagrams WHERE name = i.name
AND principal_id = p.principal_id
);
END
GO
在创建了几个图表之后,以下是这些用户的简化版本的Object Explorer:
现在,dbo
将收集一堆图的副本,这也许不是必需的,但是您可能希望在大多数情况下将它们作为“主”。