我正在从 ADO 迁移到 FireDAC。将 TADOStoredProc 替换为 TFDStoredProc 后,我遇到以下问题。我的 _OpenStp 过程打开一个在其参数列表中具有默认值的存储过程,并且我不想传递所有这些参数。例如
CREATE PROCEDURE [dbo].[usp_SearchDocument]
@User_Id INT
, @Window_Id INT = 10
, @Page INT = 1
...
我的程序的核心:
procedure _OpenStp(
const AConnection: TFDConnection;
var AStp: TFDStoredProc;
const AStpName: string;
const AParamNameA: array of string;
const AParamValueA: array of Variant);
var
i: Integer;
begin
if AStp <> nil then
begin
if AStp.Active then
AStp.Close;
end
else
AStp := TFDStoredProc.Create(nil);
AStp.Connection := AConnection;
AStp.StoredProcName := AStpName;
AStp.Prepare;
for i := Low(AParamNameA) to High(AParamNameA) do
AStp.Params.ParamByName(AParamNameA[i]).Value := AParamValueA[i];
AStp.Open;
end;
调用的Delphi代码:
_OpenStp(SomeConnection, SomeStp, 'usp_SearchDocument',
['User_Id'], [150]);
根据 SQL Server Profiler,调用是:
exec [dbo].[usp_SearchDocument]
@User_Id=150,
@Window_Id=NULL,
@Page=NULL
TFDStoredProc.Prepare 似乎没有查询 sp 参数的默认值。当我使用 _OpenStp 过程的 ADO 对应项时,TADOStoredProc.Parameters.Refresh 方法完成了这项工作:
procedure _OpenStp(
const AConnection: TADOConnection;
var AStp: TADOStoredProc;
const AStpName: string;
const AParamNameA: array of string;
const AParamValueA: array of Variant);
begin
if AStp <> nil then
begin
if AStp.Active then
AStp.Close;
end
else
AStp := TADOStoredProc.Create(nil);
AStp.Connection := AConnection;
AStp.ProcedureName := AStpName;
AStp.Parameters.Refresh;
for i := 0 to Length(AParamNameA) - 1 do
AStp.Parameters.ParamByName(AParamNameA[i]).Value := AParamValueA[i];
AStp.Open;
end;
SQL Server 探查器:
exec usp_SearchDocument 150,default,default
不幸的是,无法重写代码来传递所有参数,我必须依赖 sp 参数默认值。有没有办法修改我的 _OpenStp 程序的 FireDAC 版本来实现此目标?
编辑:我什至没有有关参数类型的信息(请参阅 _OpenStp 过程),我只知道它们的名称和要设置的值,因此我无法以编程方式创建 TFDParams。
Edit#2:删除不必要的参数后抛出
EArgumentOutOfRangeException
:
for i := AStp.ParamCount - 1 downto 0 do
if AStp.Params[i].Name <> '@RETURN_VALUE' then
begin
ExistsInArray := False;
for j := Low(AParamNameA) to High(AParamNameA) do
if Char.ToLower(AStp.Params[i].Name) = Char.ToLower(Format('@%s', [AParamNameA[j]])) then
begin
ExistsInArray := True;
Break;
end;
if not ExistsInArray then
AStp.Params.Delete(i);
end;
我们也遇到了同样的问题。删除参数后添加:
AStp.FetchOptions.Items := AStp.FetchOptions.Items - [fiMeta];
AStp.Unprepare;
AStp.Prepare;