在调用存储过程时,对参数的一个个赋值应该说是比较繁琐的,而且由于每个存储过程都不一样,不断的重复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