SqlCommandBuilder() 为基础表创建插入/更新,而不是为视图创建插入/更新
本文关键字:插入 更新 创建 视图 为基础 SqlCommandBuilder | 更新日期: 2023-09-27 17:55:10
我有两个模式,像这样:
- 模式"数据"-->保存表,没有人可以从外部访问它们
- 架构 'ui' --> 包含可从外部访问的视图;这个想法是您可以选择/删除/更新/插入这些视图。因此,我正在做所有权链。
例如:
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();
==> 然后在下面,插入不起作用!
[编辑]:
SqlCommandBuilder 正在分析视图,而不是创建类似
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命令。但是,现在可能存在另一种解决方案吗?但是,到目前为止我没有找到...
[/编辑]
好的,现在答案肯定是:
SqlCommandBuilder
试图变得"聪明"。如果您使用类似 SELECT * FROM vwTest
的命令打开它,那么它会分析视图并为基础表创建命令,例如 INSERT into tblTest
...
所以问题是:SqlCommandBuilder
为基础表而不是视图创建命令。
溶液:
到目前为止,我还没有找到改变SqlCommandBuilder
行为的方法。
因此,我重写了所有加载和更新,现在我正在手动完成所有操作。现在,装载纯粹是用SqlDataReader
进行的——不用SqlDataAdapter
装载到DataTable
中。并且所有更新都是通过创建和执行SqlCommand
来完成的,无需SqlCommandBuilder
。
这是很多工作,但作为奖励,该应用程序现在速度极快。加载速度远远快于SqlCommandBuilder
和SqlDataAdapter
。可能我会在某个时候进行基准比较。但是,当加载需要 5 秒时,现在它是"立即"完成的。
请注意所有权链接文档的这一部分:
通过链访问对象时,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
架构中的对象与data
架构中的对象进行交互。