SqlCommandBuilder()为基础表创建插入/更新,而不是视图

时间:2015-06-10 06:59:22

标签: c# .net sql-server azure-sql-database sql-server-2014

我有两个模式,如下:

  • 架构'数据' - >持有表格,没有人可以从外面访问它们
  • 架构' 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();

==>然后在下面, 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]

2 个答案:

答案 0 :(得分:1)

好的,答案现在肯定是:

SqlCommandBuilder正试图成为智能"。如果使用SELECT * FROM vwTest之类的命令打开它,则会分析视图并为基础表创建命令,例如INSERT into tblTest ...

所以问题是:SqlCommandBuilder为基础表而不是视图创建命令。

解决方案:

到目前为止,我发现无法改变SqlCommandBuilder的行为。

因此,我重写了所有的加载和更新,现在我手动完成所有操作。现在加载仅使用SqlDataReader - 而无需加载到DataTable SqlDataAdapter。所有更新都是通过创建和执行SqlCommand完成的,而不是SqlCommandBuilder

这是一项很多工作,但作为奖励,应用程序现在快速。与SqlCommandBuilderSqlDataAdapter相比,加载的速度更快。可能我会在某个时候进行基准比较。但是当负载花了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}中的对象进行交互架构。