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

我有两个模式,像这样:

  • 模式’数据’ – >保存表,没有人可以从外部访问它们
  • Schema’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 ; 

但该角色对Schema’数据’没有任何权利!

这种设置的好处是你可以应用行级安全性。 使用视图中的wherefilter,您只能选择允许用户查看的记录。

如上所述,它在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

这是一项很多工作,但作为奖励,应用程序现在非常快速 。 加载速度远远快于SqlCommandBuilderSqlDataAdapter 。 可能我会在某个时候进行基准比较。 但是当负载花了5秒钟时,它现在“立即”完成。

请注意所有权链接文档的这一部分:

当通过链访问对象时,SQL Server首先将对象的所有者与调用对象的所有者进行比较。 这是链中的前一个链接。 如果两个对象具有相同的所有者 ,则不会评估对引用对象的权限。“

因此,为了使所有权链接正常工作,您的表和视图必须由相同的原则拥有

您可以通过在对象上执行ALTER AUTHORIZATION sql语句来更改视图的所有者或表的所有者。
请注意,此语句仅更改所有者,而不更改对象所属的架构。 在您的情况下,我建议将UI架构的所有者更改为Data架构的同一所有者,同时保持使用UI架构的数据库原则的权限不变。

 ALTER AUTHORIZATION ON SCHEMA::UI TO ; 

注意: 是我使用的占位符,因为我不知道所有者名称。

这样,您的应用程序用户仍然只能访问ui架构中的任何内容,但是所有权链接允许ui架构中的对象与data架构中的对象进行交互。