我有两个模式,如下:
例如:
create table data.tblTest (TestKey int not null primary key);
create view ui.vwTest as select * from data.tblTest;
现在,如果我以SQL Studio身份连接用户,一切正常:
select * from ui.vwTest; -- WORKS (this is correct)
select * from data.tblTest; -- ERROR (this is correct)
insert into ui.vwTest (TestKey) values (17); -- WORKS (this is correct)
insert into data.tblTest (TestKey) values (17); -- ERROR (this is correct)
但是,如果我在.NET / C#中编写一个使用SqlCommandBuilder的程序:
SqlDataAdapter ada = new SqlDataAdapter('select * from ui.vwTest', conn);
SqlCommandBuilder b = new SqlCommandBuilder(mSQLAda);
ada.UpdateCommand = b.GetUpdateCommand();
ada.InsertCommand = b.GetInsertCommand();
ada.DeleteCommand = b.GetDeleteCommand();
==>然后在下面, INSERT不工作!
[编辑]:
SqlCommandBuilder正在分析View,而不是创建像
这样的命令INSERT INTO ui.vwTest ...
正在创建
INSERT INTO data.tblTest ...
事实上,SqlCommandBuilder试图成为智能"并访问视图的基础表,而不是访问视图。
问题:是否可以更改此行为?
顺便说一下,为了更清楚,我在这里做所有权链接。我的用户有权查看架构 ui 中的观看次数,但他们无权使用架构数据。但是,由于所有权限制,用户可以通过架构数据中的视图间接访问表。
详细说明,用户被附加到自定义角色,例如" role_user",并且该角色拥有架构的权限,如下所示:
GRANT SELECT, UPDATE, INSERT, DELETE ON SCHEMA ui TO role_user ;
但该角色对架构'数据'没有任何权利。 !!
此设置的好处是您可以应用行级安全性。使用视图中的where过滤器,您只能选择允许用户查看的记录。
如上所述,它在SQL窗口中工作正常,但不适用于SQLCommandBuilder。 SQLCommandBuilder分析视图,并尝试直接访问基础表,而不是访问视图。
7年前,有人问过:https://stackoverflow.com/a/320684/2504785 然后他的解决方案是自己编写SQL命令。 但可能,现在还有另一种解决方案吗?但是,到目前为止我没有发现......[/ EDIT]
答案 0 :(得分:1)
好的,答案现在肯定是:
SqlCommandBuilder
正试图成为智能"。如果使用SELECT * FROM vwTest
之类的命令打开它,则会分析视图并为基础表创建命令,例如INSERT into tblTest
...
所以问题是:SqlCommandBuilder
为基础表而不是视图创建命令。
解决方案:
到目前为止,我发现无法改变SqlCommandBuilder
的行为。
因此,我重写了所有的加载和更新,现在我手动完成所有操作。现在加载仅使用SqlDataReader
- 而无需加载到DataTable
SqlDataAdapter
。所有更新都是通过创建和执行SqlCommand
完成的,而不是SqlCommandBuilder
。
这是一项很多工作,但作为奖励,应用程序现在快速。与SqlCommandBuilder
和SqlDataAdapter
相比,加载远的速度更快。可能我会在某个时候进行基准比较。但是当负载花了5秒钟时,现在就完成了#34;立即进行了#34;。
答案 1 :(得分:0)
请注意ownership chaining文档的这一部分:
当通过链访问对象时,SQL Server首先将对象的所有者与调用对象的所有者进行比较。这是链中的前一个链接。 如果两个对象具有相同的所有者,则引用对象的权限为未评估。"
因此,为了使所有权链接正常运行,您的表格和视图必须按照相同的原则拥有。
您可以通过在对象上执行ALTER AUTHORIZATION
sql语句来更改视图的所有者或表的所有者。
请注意,此语句仅更改所有者,而不更改对象所属的架构。
在您的情况下,我建议将UI
架构的所有者更改为Data
架构的同一所有者,同时保持使用UI
架构的数据库原则的权限。
ALTER AUTHORIZATION ON SCHEMA::UI TO <owner_of_the_data_schema>;
注意:<owner_of_the_data_schema>
是我使用的占位符,因为我不知道所有者名称。
这样,您的应用程序用户仍然只能访问ui
架构中的任何内容,但所有权链接允许ui
架构中的对象与{{1}中的对象进行交互架构。