原创  使用一个TADOStoredProc执行多个存储过程 收藏

    在用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... ) | 编辑| 举报| 收藏

旧一篇:用Delphi动态改变页面内容 | 新一篇:一个绝对完整的餐饮系统源代码(含PDA点菜)

  • 发表评论
  • 评论内容:
  •  
Copyright © operfume
Powered by CSDN Blog