You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi TADOQuery Recordset.Resync需底层表SELECT权限问题求助

问题

用Delphi 10.1(Berlin)开发的VCL应用,通过ADO组件连接SQL Server 2019,Provider为Microsoft OLE DB Provider for SQL Server。SQL Server中存在表OMEGACA.ACC_POL,基于该表创建了视图OMEGACA.V_ACC_POL,应用使用的账号仅拥有此视图的SELECT权限,无底层表的访问权限。

Form1通过TADOQuery执行select * from OMEGACA.V_ACC_POL将数据展示在DBGrid中,Form2用于编辑选中记录。编辑完成后,尝试用以下代码刷新当前记录(避免重新查询整个数据集):

form1.ADOQuery1.UpdateCursorPos;
form1.ADOQuery1.Recordset.Resync(adAffectCurrent, adResyncAllValues);
form1.ADOQuery1.Resync([rmExact,rmCenter]);

运行后报错:

The SELECT permission was denied on the object 'ACC_POL', database 'MY_DB', schema 'OMEGACA'.

给账号授予底层表的SELECT权限后恢复正常,但需求是通过视图隔离表、用存储过程处理增删改,同时实现单条记录刷新,不想开放底层表权限。

原因

ADO的Resync方法会绕开视图直接访问底层表同步数据。即便查询基于视图,OLE DB Provider执行Resync时仍会尝试从原表获取数据,而应用账号无底层表的SELECT权限,因此触发权限错误。

解决办法

方法1:重新查询单条记录覆盖当前行

放弃使用Resync,通过主键从视图查询最新数据,再更新当前记录的字段值:

var
  TempQuery: TADOQuery;
  CurrentID: Integer;
begin
  CurrentID := form1.ADOQuery1.FieldByName('POLICY_ID').AsInteger;
  
  TempQuery := TADOQuery.Create(nil);
  try
    TempQuery.Connection := form1.ADOQuery1.Connection;
    TempQuery.SQL.Text := 'SELECT * FROM OMEGACA.V_ACC_POL WHERE POLICY_ID = :ID';
    TempQuery.Parameters.ParamByName('ID').Value := CurrentID;
    TempQuery.Open;
    
    if not TempQuery.Eof then
    begin
      form1.ADOQuery1.Edit;
      // 逐个更新需要同步的字段
      form1.ADOQuery1.FieldByName('POLICY_NAME').AsString := TempQuery.FieldByName('POLICY_NAME').AsString;
      form1.ADOQuery1.FieldByName('POLICY_DESC').AsString := TempQuery.FieldByName('POLICY_DESC').AsString;
      form1.ADOQuery1.FieldByName('STATUS_ID').AsInteger := TempQuery.FieldByName('STATUS_ID').AsInteger;
      // ... 其他字段依次更新
      form1.ADOQuery1.Post;
    end;
  finally
    TempQuery.Free;
  end;
end;

该方式全程仅访问视图,符合权限隔离要求。

方法2:配置可更新视图(如需直接通过视图修改数据)

当前视图基于单表、无聚合/分组且包含主键,本身具备可更新条件。修改视图并添加WITH CHECK OPTION,同时授予账号视图的UPDATE权限:

ALTER VIEW [OMEGACA].[V_ACC_POL]
WITH CHECK OPTION
AS
SELECT  
POLICY_ID, POLICY_NAME, POLICY_DESC, 
STATUS_ID, 
Status_Code = CASE 
    WHEN STATUS_ID = 0 THEN 'Inactive'
    WHEN STATUS_ID = 1 THEN 'Active'
    ELSE 'Error'
END,
-- 其余视图内容保持不变
FROM OMEGACA.ACC_POL
GO

-- 授予应用账号视图的更新权限
GRANT UPDATE ON OMEGACA.V_ACC_POL TO [你的应用账号]

之后可直接通过TADOQuery.Edit/Post更新视图数据,刷新仍使用方法1的单条查询方式,避免触发底层表访问。

方法3:通过存储过程获取单条最新记录

创建存储过程封装视图查询逻辑,授予账号存储过程执行权限:

CREATE PROCEDURE [OMEGACA].[GetPolicyById]
    @PolicyID INT
AS
BEGIN
    SELECT * FROM OMEGACA.V_ACC_POL WHERE POLICY_ID = @PolicyID
END
GO

-- 授予应用账号存储过程执行权限
GRANT EXECUTE ON OMEGACA.GetPolicyById TO [你的应用账号]

应用中调用存储过程获取数据并更新当前行,逻辑与方法1一致,仅查询方式替换为存储过程:

var
  TempQuery: TADOQuery;
  CurrentID: Integer;
begin
  CurrentID := form1.ADOQuery1.FieldByName('POLICY_ID').AsInteger;
  
  TempQuery := TADOQuery.Create(nil);
  try
    TempQuery.Connection := form1.ADOQuery1.Connection;
    TempQuery.SQL.Text := 'EXEC OMEGACA.GetPolicyById :ID';
    TempQuery.Parameters.ParamByName('ID').Value := CurrentID;
    TempQuery.Open;
    
    if not TempQuery.Eof then
    begin
      form1.ADOQuery1.Edit;
      // 更新字段...
      form1.ADOQuery1.Post;
    end;
  finally
    TempQuery.Free;
  end;
end;
附:原表与视图定义

表定义

CREATE TABLE [OMEGACA].[ACC_POL](
    [POLICY_ID] [int] IDENTITY(1,1) NOT NULL,
    [POLICY_NAME] [nvarchar](200) NOT NULL,
    [POLICY_DESC] [nvarchar](1000) NULL,
    [STATUS_ID] [int] NOT NULL,
    [RULE_EVAL] [int] NOT NULL,
    [AUDIT_OPTION] [int] NOT NULL,
    [FORMULA] [nvarchar](2000) NULL,
    [DEBUG_LOG] [int] NOT NULL,
    [USER_APPLY] [int] NOT NULL,
    [USE_CACHE] [int] NOT NULL,
    [DATE_UPD] [datetime] NULL,
    [USER_UPD] [nvarchar](200) NULL,
    [DATE_CREATED] [datetime] NOT NULL,
    [USER_CREATED] [nvarchar](200) NOT NULL,
 CONSTRAINT [ACC_POL_PK] PRIMARY KEY CLUSTERED 
(
    [POLICY_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

视图定义

CREATE   VIEW [OMEGACA].[V_ACC_POL]
AS
SELECT  
POLICY_ID, POLICY_NAME, POLICY_DESC, 

STATUS_ID, 
Status_Code = 
CASE 
    WHEN STATUS_ID = 0 THEN 'Inactive'
    WHEN STATUS_ID = 1 THEN 'Active'
    ELSE 'Error'
END,

RULE_EVAL, 
Rule_Eval_Code = 
CASE 
    WHEN RULE_EVAL = 1 THEN 'Any True'
    WHEN RULE_EVAL = 2 THEN 'All True'
    WHEN RULE_EVAL = 3 THEN 'Formula'
    ELSE 'Error'
END,

AUDIT_OPTION, 
Audit_Option_Code =
CASE 
    WHEN AUDIT_OPTION = 0 THEN 'Disabled'
    WHEN AUDIT_OPTION = 1 THEN 'On Failure'
    WHEN AUDIT_OPTION = 2 THEN 'On Success/Failure'
    ELSE 'Error'
END,

FORMULA,

DEBUG_LOG, 
Debug_Log_Code = 
CASE 
    WHEN DEBUG_LOG = 0 THEN 'No'
    WHEN DEBUG_LOG = 1 THEN 'Yes'
    ELSE 'Error'
END,

USER_APPLY,
User_Apply_Code = 
CASE 
    WHEN USER_APPLY = 0 THEN 'All Users'
    WHEN USER_APPLY = 1 THEN 'Users Apply'
    WHEN USER_APPLY = 2 THEN 'Users Exclude'
    ELSE 'Error'
END,

USE_CACHE,
Use_Cache_Code = 
CASE 
    WHEN USE_CACHE = 0 THEN 'No'
    WHEN USE_CACHE = 1 THEN 'Yes'
    ELSE 'Error'
END,

DATE_UPD, USER_UPD,

DATE_CREATED, USER_CREATED

FROM OMEGACA.ACC_POL

GO

内容的提问来源于stack exchange,提问作者altink

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 12:48:11