【问题标题】:SqlCommandBuilder() creates insert/update for underlying tables instead for a viewSqlCommandBuilder() 为基础表而不是视图创建插入/更新
【发布时间】:2015-08-25 06:50:40
【问题描述】:

我有两个架构,像这样:

  • Schema 'data' --> 保存表,没有人可以从外部访问它们
  • 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 DOES NOT WORK

[编辑]:

SqlCommandBuilder 正在分析视图,而不是创建类似的命令

INSERT INTO ui.vwTest ...

它正在创建

INSERT INTO data.tblTest ...

所以事实上,SqlCommandBuilder 试图“智能”并访问视图的底层表,而不是访问视图。

问题:这种行为可以改变吗?

顺便说一句,为了更清楚起见,我在这里进行所有权链接

我的用户有权查看架构 ui 中的视图,但他们无权查看架构 数据。但是,由于所有权变更,用户可以通过模式 data 中的视图间接访问表。

详细地说,用户被附加到一个自定义角色,例如“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]

【问题讨论】:

  • 我认为问题不在于SqlCommandBuilder。您的视图与表位于不同的架构中,我的猜测是来自 c# 的连接没有访问此架构或此表的权限。
  • @ZoharPeled:在代码中您看到,视图已被访问,但在错误消息中提到了该表。 Giosco 不想授予对表的访问权限,只是为了查看。
  • 我目前没有可以玩的服务器,但是如果没有记忆,您需要对视图从中选择的所有表具有选择权限,但是,如果您使用存储过程,您只需要执行权限。我会在几个小时后尝试验证。
  • 对不起@ZoharPeled,你是对的。 Giosco 看到这个:msdn.microsoft.com/en-us/library/ms180800.aspx#Security
  • 或许这就是对这种情况的解释:technet.microsoft.com/en-us/library/dd283095(v=sql.100).aspx

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


【解决方案1】:

好的,现在的答案是:

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

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

解决方案:

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

因此,我重写了所有加载和更新,现在我正在手动完成所有操作。现在完全使用SqlDataReader 进行加载——无需使用SqlDataAdapter 加载到DataTable。并且所有更新都是通过创建和执行SqlCommand 完成的,没有SqlCommandBuilder

这是一项艰巨的工作,但作为奖励,该应用程序现在速度非常快。加载速度比SqlCommandBuilderSqlDataAdapter。可能我会在某个时候进行基准比较。但是,当加载之前需要 5 秒时,现在“立即”完成。

【讨论】:

    【解决方案2】:

    请注意ownership chaining 文档的这一部分:

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

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

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

    ALTER AUTHORIZATION ON SCHEMA::UI TO <owner_of_the_data_schema>;
    

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

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

    【讨论】:

    • 当然,这个答案只有在表的所有者和视图的所有者实际上不同的情况下才有效。 OP 的“insert into ui.vwTest (TestKey) values (17); -- WORKS (this is correct)”向我表明这部分已经正确设置。
    • @hvd 请注意,当 OP 从 SSMS 执行此语句时,这部分有效,这意味着他可能以不同的数据库用户身份登录,而不是他在 c# 应用程序中使用的那个用户...
    • 也许(我不相信——为什么来自 SSMS 的登录会使用不同的用户?),但无论哪种方式,仍然不是有权插入表的用户:甚至失败根据问题,来自 SSMS。
    • 在我工作过的所有地方的大部分时间里,开发人员都在使用 sa(或其他一些高权限原则)连接到 SSMS。我相信这里也是如此。如果你以 sa 的身份连接,那么所有权链接的失败没有任何意义,因为 sa 显然拥有所需的所有权限...
    • 是的,但 sa 通常也有权将数据插入原始表,而 OP 实际使用的用户则没有。无论如何,现在,我们都在猜测。有根据的猜测,但仍然猜测。 OP 肯定可以评论您的答案是否有效。
    猜你喜欢
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多