SqlCommandBuilder() 为基础表而不是视图创建 insert/update
SqlCommandBuilder() creates insert/update for underlying tables instead for a view
我有两个模式,像这样:
- Schema 'data' --> 保存表,没有人可以从外部访问它们
- Schema 'ui' --> 保存可从外部访问的视图;这个想法是您可以 select/delete/update/insert 这些观点。因此,我正在做 所有权链接。
例如:
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 正在分析视图,而不是创建像
这样的命令
INSERT INTO ui.vwTest ...
正在创建
INSERT INTO data.tblTest ...
所以实际上,SqlCommandBuilder 试图成为"intelligent" 并访问视图的基础表,而不是访问视图。
问题:这个行为可以改变吗?
顺便说一句,为了更清楚一点,我在这里进行所有权链接。
我的用户有权查看架构 ui 中的视图,但他们无权查看架构 数据。但是,由于所有权变化,用户可以通过模式 data.
中的视图间接访问表
详细来说,用户已附加到自定义角色,例如"role_user",并且角色对schema有权限,如下:
GRANT SELECT, UPDATE, INSERT, DELETE ON SCHEMA ui TO role_user ;
但该角色对架构没有任何权利 'data' !!
此设置的好处是您可以应用行级安全性。使用视图中的 where 过滤器,您可以 select 仅允许用户查看记录。
如前所述,它在 SQL window 中工作正常,但在 SQLCommandBuilder 中却不行。 SQLCommandBuilder 分析视图,并尝试直接访问基础表,而不是访问视图。
7 年前,有人这样问:
然后他的解决方案是自己编写 SQL 命令。
但可能,现在存在另一种解决方案?但是,到目前为止我发现 none ...
[/编辑]
请注意 ownership chaining 文档的这一部分:
When an object is accessed through a chain, SQL Server first compares the owner of the object to the owner of the calling object. This is the previous link in the chain. If both objects have the same owner, permissions on the referenced object are not evaluated."
因此,为了使所有权链接正常工作,您的 table 和视图必须按照相同的原则拥有。
您可以通过对对象执行 ALTER AUTHORIZATION
sql 语句来更改视图的所有者或 table 的所有者。
请注意,此语句仅更改所有者,而不更改对象所属的模式。
对于您的情况,我建议将 UI
架构的所有者更改为 Data
架构的同一所有者,同时保持使用 UI
架构的数据库原则的权限不变。
ALTER AUTHORIZATION ON SCHEMA::UI TO <owner_of_the_data_schema>;
注意:<owner_of_the_data_schema>
是我使用的占位符,因为我不知道所有者姓名。
这样,您的应用程序用户仍然只能访问 ui
架构中的任何内容,但所有权链接允许 ui
架构中的对象与 ui
架构中的对象交互=18=] 架构。
OK,现在确定的答案是:
SqlCommandBuilder
正试图成为 "intelligent"。如果您使用 SELECT * FROM vwTest
之类的命令打开它,那么它会分析视图并为底层 table 创建命令,例如 INSERT into tblTest
...
所以问题是:SqlCommandBuilder
为底层table创建命令,而不是为视图创建命令。
解法:
到目前为止,我没有找到改变 SqlCommandBuilder
行为的方法。
因此,我重写了所有的加载和更新,现在都是手动完成。加载现在完全通过 SqlDataReader
进行——无需使用 SqlDataAdapter
加载到 DataTable
。所有更新都是通过创建和执行 SqlCommand
完成的,没有 SqlCommandBuilder
.
工作量很大,但作为回报,应用程序现在速度极快。加载速度比 SqlCommandBuilder
和 SqlDataAdapter
快 。可能我会在某个时候进行基准比较。但是以前加载需要 5 秒,现在已经完成 "immediatedly"。
我有两个模式,像这样:
- Schema 'data' --> 保存表,没有人可以从外部访问它们
- Schema 'ui' --> 保存可从外部访问的视图;这个想法是您可以 select/delete/update/insert 这些观点。因此,我正在做 所有权链接。
例如:
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 正在分析视图,而不是创建像
这样的命令INSERT INTO ui.vwTest ...
正在创建
INSERT INTO data.tblTest ...
所以实际上,SqlCommandBuilder 试图成为"intelligent" 并访问视图的基础表,而不是访问视图。
问题:这个行为可以改变吗?
顺便说一句,为了更清楚一点,我在这里进行所有权链接。
我的用户有权查看架构 ui 中的视图,但他们无权查看架构 数据。但是,由于所有权变化,用户可以通过模式 data.
中的视图间接访问表详细来说,用户已附加到自定义角色,例如"role_user",并且角色对schema有权限,如下:
GRANT SELECT, UPDATE, INSERT, DELETE ON SCHEMA ui TO role_user ;
但该角色对架构没有任何权利 'data' !!
此设置的好处是您可以应用行级安全性。使用视图中的 where 过滤器,您可以 select 仅允许用户查看记录。
如前所述,它在 SQL window 中工作正常,但在 SQLCommandBuilder 中却不行。 SQLCommandBuilder 分析视图,并尝试直接访问基础表,而不是访问视图。
7 年前,有人这样问: 然后他的解决方案是自己编写 SQL 命令。 但可能,现在存在另一种解决方案?但是,到目前为止我发现 none ...
[/编辑]
请注意 ownership chaining 文档的这一部分:
When an object is accessed through a chain, SQL Server first compares the owner of the object to the owner of the calling object. This is the previous link in the chain. If both objects have the same owner, permissions on the referenced object are not evaluated."
因此,为了使所有权链接正常工作,您的 table 和视图必须按照相同的原则拥有。
您可以通过对对象执行 ALTER AUTHORIZATION
sql 语句来更改视图的所有者或 table 的所有者。
请注意,此语句仅更改所有者,而不更改对象所属的模式。
对于您的情况,我建议将 UI
架构的所有者更改为 Data
架构的同一所有者,同时保持使用 UI
架构的数据库原则的权限不变。
ALTER AUTHORIZATION ON SCHEMA::UI TO <owner_of_the_data_schema>;
注意:<owner_of_the_data_schema>
是我使用的占位符,因为我不知道所有者姓名。
这样,您的应用程序用户仍然只能访问 ui
架构中的任何内容,但所有权链接允许 ui
架构中的对象与 ui
架构中的对象交互=18=] 架构。
OK,现在确定的答案是:
SqlCommandBuilder
正试图成为 "intelligent"。如果您使用 SELECT * FROM vwTest
之类的命令打开它,那么它会分析视图并为底层 table 创建命令,例如 INSERT into tblTest
...
所以问题是:SqlCommandBuilder
为底层table创建命令,而不是为视图创建命令。
解法:
到目前为止,我没有找到改变 SqlCommandBuilder
行为的方法。
因此,我重写了所有的加载和更新,现在都是手动完成。加载现在完全通过 SqlDataReader
进行——无需使用 SqlDataAdapter
加载到 DataTable
。所有更新都是通过创建和执行 SqlCommand
完成的,没有 SqlCommandBuilder
.
工作量很大,但作为回报,应用程序现在速度极快。加载速度比 SqlCommandBuilder
和 SqlDataAdapter
快 。可能我会在某个时候进行基准比较。但是以前加载需要 5 秒,现在已经完成 "immediatedly"。