我对FireDAC比较陌生。我希望能够动态地“动态”调用存储过程。到目前为止,我有以下内容:
function TForm21.ExecuteStoredProc(aSPName: string; aParams: TADParams): Boolean;
var
LSP: TADStoredProc;
i: Integer;
begin
LSP := TADStoredProc.Create(nil);
try
LSP.Connection := ADConnection1;
LSP.StoredProcName := aSPName;
LSP.Prepare;
for i := 0 to aParams.Count - 1 do
begin
LSP.Params[i].Value := aParams[i].Value;
end;
LSP.ExecProc;
finally
LSP.Free;
end;
Result := True;
end;
我用
打电话procedure TForm21.Button1Click(Sender: TObject);
var
LParams: TADParams;
begin
LParams := TADParams.Create;
LParams.Add.Value := 612;
LParams.Add.Value := '2008';
ExecuteStoredProc('HDMTEST.dbo.spARCHIVE_HISTORY_DATA', LParams);
end;
但是,存储过程无法执行。也就是说,代码运行正常,没有显示错误消息,但存储过程不会运行。
更多信息 - 如果我删除组件并在代码中设置params,它运行正常。
任何人都知道我错过了什么?
答案 0 :(得分:2)
看到这个q一段时间没有得到回答,我想我试图让代码工作而不使用评论中的线索,发现它并不像我想象的那么容易。
我立刻陷入了SP params。我发现了这个
http://docwiki.embarcadero.com/RADStudio/XE5/en/TFDQuery,_TFDStoredProc_and_TFDUpdateSQL_Questions
说
"If you have difficulties with manual definition of parameters,
populate the Params collection automatically and check how the
parameters are defined. Then compare that to your code. "
但我无法自动找到一种方式"填写Params。我在EMBA上问道 FireDac新闻组和FD作者Dimitry Arefiev亲切地解释说 您可以通过检查FetchOptions是否包含fiMeta,然后清除并设置FDStoredProc的StoredProcName来实现。
在我的SqlServer上的pubs演示数据库中使用StoredProc定义如下:
create procedure test(@ANumber int, @AName varchar(20))
as
begin
select
@ANumber * 2 as "Number",
@AName + @AName as "Name"
end
我改变了OP代码中的几个部分,如此
[...]
LSP.Params.Clear;
LSP.StoredProcName := '';
LSP.FetchOptions.Items := LSP.FetchOptions.Items + [fiMeta];
LSP.StoredProcName := aSPName;
LSP.Prepare;
Assert(LSP.ParamCount > 0);
for i := 0 to aParams.Count - 1 do
begin
LSP.Params.ParamByName(aParams[i].Name).Value := aParams[i].Value;
end;
[...]
procedure TForm21.Button1Click(Sender: TObject);
var
LParams: TFDParams;
Param : TFDParam;
begin
LParams := TFDParams.Create;
Param := LParams.Add;
Param.Name := '@ANumber';
Param.Value := 612;
Param := LParams.Add;
Param.Name := '@AName';
Param.Value := '2008';
ExecuteStoredProc('test', LParams);
end;
它工作正常。
OP提到他首先遇到了SP无法执行的问题 但是他发现,如果他“放弃”某个组件并在代码中设置了参数,那么它就能发挥作用。所以我认为我在这里包含一个控制台应用程序,当然必须在代码中完成所有操作。这并不困难,但是我使用Uses条款的时间是我将这个作为答案发布的主要原因,以供将来参考。没有正确的用途,你就会因为各种类工厂的缺失而抱怨错误。
控制台应用(在XE6中创建和测试):
program ConsoleStoredProcProject3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, FireDac.DApt, FireDAC.Stan.Def, FireDAC.Stan.ASync,
FireDAC.Stan.Param, FireDAC.Stan.Option, FireDAC.Comp.Client,
FireDAC.Phys.MSSQL, VCL.ClipBrd;
procedure TestSP;
var
Connection : TFDConnection;
StoredProc : TFDStoredProc;
Param : TFDParam;
begin
Connection := TFDConnection.Create(Nil);
Connection.DriverName := 'MSSQL';
Connection.Params.Values['Server'] := // your server name'';
Connection.Params.Values['Database'] := 'pubs';
Connection.Params.Values['user_name'] := 'user'; // adjust to suit
Connection.Params.Values['password'] := 'password'; // ditto
Connection.LoginPrompt := False;
Connection.Connected := True;
StoredProc := TFDStoredProc.Create(Nil);
StoredProc.Connection := Connection;
StoredProc.FetchOptions.Items := StoredProc.FetchOptions.Items + [fiMeta];
StoredProc.StoredProcName := 'test';
StoredProc.Prepare;
Param := StoredProc.Params.ParamByName('@ANumber');
Param.Value := 333;
Param := StoredProc.Params.ParamByName('@AName');
Param.Value := 'A';
StoredProc.Active := True;
WriteLn(StoredProc.FieldByName('Number').AsInteger);
WriteLn(StoredProc.FieldByName('Name').AsString);
ReadLn;
end;
begin
try
TestSP;
except
on E: Exception do
Clipboard.AsText := E.Message;
end;
end.