在用Delphi开发系统中,在需要用到很多存储过程时,一般的做法是每个存储过程用一个TADOStoredProc来执行。当存储过程很多的时候显得很烦琐,TDataModal上密密麻麻一片。尤其是在做三层架构的系统,每个TADOStoredProc还必须写一个接口函数来供客户端程序调用,显得特别麻烦,不灵活。因此,如果只用一个TADOStoredProc和一个接口函数就能够调用所有存储过程的话就太方便了。对于Delphi来说,实现这样一个目标还不是小菜一碟(当然,这需要一定的经验,不熟悉的话可能不容易做好)。
下面是中间层接口函数的代码:
{TPublData是一个远程数据模块
ProcName 需要调用的存储过程名
pParams 传递给存储过程的参数
sResult 存储过程返回到客户端的参数}
function TPublData.executeProc( ProcName: WideString;
pParams: OleVariant; var sResult: OleVariant): Integer;
var
i:Integer;
v:TParameter;
outn,j:Integer;
begin
StoredProc1.Parameters.Clear;
StoredProc1.ProcedureName := ProcName+';1';
{直接从系统表中获取存储过程的参数声明,name-参数名称,xtype-参数类型,
isoutparam-是否是输出参数,length-参数宽度}
execQuery.SQL.Clear;
execQuery.SQL.Add('select b.name,b.xtype,b.isoutparam,b.length');
execQuery.SQL.Add('from sysobjects a,syscolumns b');
execQuery.SQL.Add('where a.name='''+ProcName+''' and a.id=b.id');
{使用StoredProc1.Parameters.Refresh可以直接生成参数,本例根据存储过程的参数
定义生成参数}
try
execQuery.Open;
i := 0;
{SQL SERVER存储过程始终有一个@RETURN_VALUE参数}
v := StoredProc1.Parameters.AddParameter;
v.Name := '@RETURN_VALUE';
v.DataType := ftInteger;
v.Size := 0;
v.Precision := 10;
v.Direction := pdReturnValue; //@RETURN_VALUE始终是pdReturnValue类型
outn := 0; //outn用来记录输出参数的个数
while not execQuery.Eof do
begin
{在StoredProc1中增加参数对象}
v := StoredProc1.Parameters.AddParameter;
v.Name := execQuery.FieldByName('name').AsString;
{SQL SERVER系统表中存储过程参数类型用数字来表示,以下代码用来设置参数对
象的数据类型}
case execQuery.FieldByName('xtype').AsInteger of
175,167:
v.DataType := ftString;
48,52:
v.DataType := ftSmallInt;
56:
v.DataType := ftInteger;
58:
v.DataType := ftDate;
61:
v.DataType := ftDateTime;
62:
v.DataType := ftFloat;
60:
v.DataType := ftCurrency;
end;
{判断是否是输出参数,是的话设置为pdInputOutput,并且outn加1}
if execQuery.FieldByName('isoutparam').AsInteger = 1 then begin
v.Direction := pdInputOutput;
Inc(outn);
end
else
v.Direction := pdInput;
{设置参数传入的值}
v.Value := pParams[i];
v.Size := execQuery.FieldByName('length').AsInteger;
Inc(i);
execQuery.Next;
end;
finally
execQuery.Close;
end;
try
{执行存储过程}
StoredProc1.ExecProc;
Result := StoredProc1.Parameters.ParamByName('@RETURN_VALUE').Value;
{获取存储过程返回的异常信息,Result<>0时表示有异常}
Result := getProcErrMsg(StoredProc1,Result,sResult);
{如果存储过程没有异常,并且有输出参数时,需要把输出参数的值返回给客户端}
if(Result=0)and(outn>0)then begin
sResult := VarArrayCreate([0,outn-1],varVariant); //生成动态数组
j := 0;
for i:=0 to StoredProc1.Parameters.Count-1 do
if(StoredProc1.Parameters[i].Direction = pdInputOutput)or
(StoredProc1.Parameters[i].Direction = pdOutput) then begin
sResult[j] := StoredProc1.Parameters[i].Value; //把存储过程返回的参数值一一
Inc(j); //放到sResult中。
end;
end;
except
on E:Exception do begin
sResult := E.Message;
Result := -1;
end;
end;
end;
下面是客户端的代码:
{Server TDCOMConnection或者TSocketConnection
procName 存储过程名称
iArray 参数数组}
function TF_CLASSFORM.executeProc(Server: TDCOMConnection;
procName: String; iArray: array of String): Integer;
var
oData,iData:OleVariant;
i,k:Integer;
begin
{把参数数组转换为OleVariant类型}
k := High(iArray);
iData := VarArrayCreate([0,k+1],VarVariant);
for i:=0 to k do
iData[i] := iArray[i];
Result := -1;
with Server do
begin
Connected := True;
Result := AppServer.executeProc(procName,iData,oData);
_OutData := oData; {_OutData是一个变量,结合Result的值,
客户端做相应的处理}
......
end;
end;
数据库中执行存储过程产生的异常,Delphi代码无法捕获的到,需要通过TADOStoredProc采用其它手段获取,以下是代码:
function getProcErrMsg(const Proc:TCustomADODataSet;
const nResult:Integer;var sResult:OleVariant):Integer;
var
ADOErrors:Errors;
ADOError:Error;
i:Integer;
begin
try
ADOErrors := Proc.Connection.Errors;
Result := ADOErrors.Count; //异常对象个数
if Result>0 then sResult := '';
for i:=0 to Result-1 do begin
ADOError := ADOErrors.item[i]; //获取每个异常对象
sResult := sResult+#13#10+ADOError.Description; //获取每个异常的信息
end;
Proc.Connection.Connected := False;
except
on E:Exception do begin
sResult := E.Message;
Result := -1;
end;
end;
if Result=0 then Result := nResult;
end;
代码注释简单了点,相信大家很容易读懂,就不再罗嗦了。很简单吧...
发表于 @ 2008年03月27日 03:27:00 | 评论( loading... ) | 举报| 收藏