基类构建技巧 1:巧妙调用存储过程 (收集条件值与赋参数值)

    在调用存储过程时,对参数的一个个赋值应该说是比较繁琐的,而且由于每个存储过程都不一样,不断的重复COPY与修改相似的代码,既易出错,又容易使开发人员失去创作的热情。

如果有一个方法,能够根据用户选定的条件,自动去与存储过程匹配,而不用去记住每个参数的名称,既容易后续扩展(同一过程名间的不同的版本),又可能减少开发人员的工作,最重要的是,它可以作为一个通用的功能存在于系统的基类中,为整个系统提供服务。

思想:开发人员定义好存储过程后(各参数的顺序),然后在前台开发界面中,为每个参数获取条件值的来源控件也制定相同的顺序,这样由于参数名与条件值的顺序相同,只需一一对应赋值(赋值的过程中可能会涉及类型转换)

 


以下以DELPHI为例(经证实在C#中一样可行):

 

1:前台开发界面中,我们可以使用TAG属性来标识条件值的序号,然后将条件控件所属的Parent传给一个函数,这个函数将条件值依TAG顺序压入一个TStrings字符数组中:

//ct:条件值控件所位于的Parent组件,这是一个容器组件(大多时是一个Panel控件)

//StrsQry:用于存储条件值数组

Procedure GetQryStrs (ct: TWinControl; StrsQry: TStrings);
var I,ParamCount: Integer;
begin
  with ct do
  begin
    ParamCount := 0;
    For I := 0 to ct.ControlCount - 1 do
    begin
      If (Controls[I].Tag = 0) or (Controls[I].Tag >= 30) then Continue;
      Inc(ParamCount);
    end;
    For I := 0 to ParamCount - 1 do
     StrsQry.Add('');
    For I := 0 to ControlCount - 1 do
    begin
      If (Controls[I].Tag = 0) or (Controls[I].Tag >= 30) then Continue;   //这里定义最多允许30个条件值
      If Controls[I] is TCheckBox then
        StrsQry[Controls[I].Tag-1] := BoolCntStr((Controls[I] as TCheckBox).Checked)
      else If Controls[I] is TEdit then
        StrsQry[Controls[I].Tag-1] := (Controls[I] as TEdit).Text
      else If Controls[I] is TComboBox then
        StrsQry[Controls[I].Tag-1] := (Controls[I] as TComboBox).Text
      else If Controls[I] is TRadioGroup then
        StrsQry[Controls[I].Tag-1] := IntToStr((Controls[I] as TRadioGroup).ItemIndex)
      else If Controls[I] is TRadioButton then
        StrsQry[Controls[I].Tag-1] := BoolCntStr((Controls[I] as TRadioButton).Checked)
      else IF ( Controls[I] is TDateTimePicker) then
        StrsQry[Controls[I].Tag-1] := FormatDateTime('YYYY-MM-DD',(Controls[I] as TDateTimePicker).Date)
    end;  //end for
  end;
end;

上面涉及调用了一个自定义函数,这是因为在DELPHI中对SQL Server的调用当为真值时传递的是"1",而非"True":

Function BoolCntStr(value: Boolean): String;
begin
  If value then Result := '1'
  else Result := '0';
end;


上面这一步我们就得到了一个条件值的字符串数组,接下来就是要将它如何与存储过程中的参数一一匹配:

Function GetDstQuery;
var StrsQry: TStrings;
begin
  StrsQry := TStringList.Create;
  Try
    GetQryStrs(pnl_expr, StrsQry);   //pnl_expr:条件值控件所位于的Parent组件,这是一个容器组件(大多时是一个Panel控件)
    if SetspParameters("传入你的ProcedureName",StrsToVariant(StrsQry)) then  //给存储过程赋参数
       //ExecProc或OPEN;
  Finally
    StrsQry.Free;
  End;
end;

//将字符串数组转换成一个OleVaiant的数组  这在多层结构开发时便于传输

Function StrsToVariant(strs: TStrings): OleVariant;
var I: Integer;
    ParamStrs: OleVariant;
begin
  ParamStrs := VarArrayCreate([0, NegToZero( strs.count-1)],VarOleStr);
  For I := 0 to  strs.Count-1 do
    ParamStrs[I] :=  strs.Strings[I];
  Result := ParamStrs;
end;

//对存储过程的各项参数一一赋值

Function SetspParameters(spNm: string; ParamStr: OleVariant; run_sp_Nm: TADOStoredProc): Boolean;
var spNm: String;
    I: Integer;
begin
  Result := False;
  If Trim(spNm) = '' then Exit;
  run_sp_Nm.Close;
  run_sp_Nm.ProcedureName := spNm;
  run_sp_Nm.Parameters.Refresh;     //获取参数列表
  If not varIsNull(ParamStr) and VarIsArray(ParamStr) then
  begin
    For I:=0 to VarArrayHighBound(ParamStr,1) do
    begin
      case varTypeCntInt(run_sp_Nm.Parameters[I+1].DataType) of
       2:    run_sp_Nm.Parameters[I+1].Value := StrToFloat(ParamStr[I]);
       3:    run_sp_Nm.Parameters[I+1].Value := VarCntbool(ParamStr[I]);
       4:    run_sp_Nm.Parameters[I+1].LoadFromStream(OleVariantToMemoryStream(ParamStr[I]),ftBlob);
       else run_sp_Nm.Parameters[I+1].Value := ParamStr[I];
      end;
    end;  //end for
  end;
  Result := True;
end;

以下为一些在上述函数中使用到的相关函数,由函数名应该能很直接的看出它们是做什么用的:

Function  VarCntbool(value: string): Boolean;
begin
  If (Trim(value)='') or (Trim(value)='0') then
    Result := False
  else
    Result := True;
end;

Function varTypeCntInt(varType: TFieldType): Integer;
begin
  Case varType of
    ftString, ftDate, ftTime, ftDateTime, ftWideString,ftFixedChar :
      Result := 1;
    ftSmallint, ftInteger, ftWord, ftFloat, ftCurrency, ftBCD, ftLargeint,
      ftBytes :
      Result := 2;
    ftBoolean : Result := 3;
    ftBlob, ftVarBytes, ftOraBlob, ftOraClob, ftMemo: Result := 4;
    ftDataSet, ftUnknown: Result := 5;
    else
      Result := 1;
  end;
end;

Function OleVariantToMemoryStream(OV: OleVariant): TMemoryStream;
var
  Data: PByteArray;
  Size: integer;
begin
  Result := TMemoryStream.Create;
  try
    Size := VarArrayHighBound (OV, 1) - VarArrayLowBound(OV, 1) + 1;
    Data := VarArrayLock(OV);
    try
      Result.Position := 0;
      Result.WriteBuffer(Data^, Size);
    finally
      VarArrayUnlock(OV);
    end;
  except
    Result.Free;
    Result := nil;
  end;
end;


附:使用此方法,在系统更新过程中,所有的用户并不需要全部退出系统,也能实现平稳过渡,其技巧就是存储过程对参数变量使用默认值即可

    至此,我们就完成了:参数打包 -->  传递  -->  对应 -->  执行  相关的一系统工作,感兴趣的朋友,可以进而将它应用到自己的系统中去,从而减少一些开发工作。如果使用中有什么疑问,也可以联系我:e-mail: NineSkySoft@126.com,更新分享请访问我的个人网站: www.nineskysoft.com

九天.2007-01-02凌晨0:31

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值