使用TADOQuery.Locate使用字段列表和VarArray值,如果其中一个值包含#符号,我们会得到以下异常:
'Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.'
我已将其追溯到ADODB,ADODB本身似乎使用#符号作为分隔符。
有没有办法逃脱#-signs以便查询不会失败?
*编辑1 *
我错了。导致此失败的原因是一个字符串,其单符号为和。下面显示的代码失败,上面提到了错误消息。
真正让我们担心的是,当它在IDE外部以.exe运行失败时,没有运行时异常。我们只在IDE中看到异常。如果我们的程序员没有碰巧使用触发此操作的数据,我们就不会知道.Locate由于运行时错误而返回FALSE,而不是因为找不到匹配的记录。
代码:
var
SearchArray: Variant;
begin
SearchArray := VarArrayCreate([0,1], VarVariant);
SearchArray[0] := 'T#more''wo';
SearchArray[1] := 'One';
ADOQuery.Locate('FieldName1;FieldName2', SearchArray, []);
答案 0 :(得分:0)
请参阅下面的更新;我找到了一个至少值得测试的解决方法。
即使使用Sql Server表,#
也不应该被转义。
以下代码在D7..XE8
中正常工作procedure TForm1.Button1Click(Sender: TObject);
begin
AdoQuery1.Locate('country;class', VarArrayOf(['GB', Edit1.Text]), []);
end;
当Edit1.Text
包含' D#E'时,我认为您的问题必须在其他地方。重新启动机器后,尝试使用该代码进行极简主义项目。
更新:如评论中所述,.Locate
表达式存在问题
传递给GetFilterStr
(在ADODB.Pas中)包含#
后跟单引号。尝试和
为此解决了问题,我已将GetFilterStr
移植到我的代码中并且已经完成了
我注意到,我一直在尝试使用它来构建我的AdoQuery上的记录集过滤器
这是.Locate
在声明
FLookupCursor.Filter := LocateFilter;
我正在使用的代码,包括我的"更正"版本GetFilterStr
,位于下方。
我还没想到的是如何避免在
上出现异常 AdoQuery1.Recordset.Filter := S;
当过滤器表达式不产生记录时。
(顺便说一句,为方便起见,我在D7中这样做,但是使用XE8' GetFilterStr
,这就是为什么我必须将{{1}的引用注释掉的原因}})
ftFixedWideChar
更新2:请尝试以下操作:
将Data.Win.ADODB.Pas复制到您的项目目录
在其中,用上面的版本替换GetFilterExpr,确保UseOriginal 没有定义,并且在Case语句中恢复了ftFixedWideChar。
构建并运行项目
无论如何,在XE8中,我的测试平台现在正确地找到()一个以function GetFilterStr(Field: TField; Value: Variant; Partial: Boolean = False): WideString;
// From XE8 Data.Win.ADODB
var
Operator,
FieldName,
QuoteCh: WideString;
begin
QuoteCh := '';
Operator := '=';
FieldName := Field.FieldName;
if Pos(' ', FieldName) > 0 then
FieldName := WideFormat('[%s]', [FieldName]);
if VarIsNull(Value) or VarIsClear(Value) then
Value := 'Null'
else
case Field.DataType of
ftDate, ftTime, ftDateTime:
QuoteCh := '#';
ftString, ftFixedChar, ftWideString://, ftFixedWideChar:
begin
if Partial and (Value <> '') then
begin
Value := Value + '*';
Operator := ' like '; { Do not localize }
end;
{.$define UseOriginal}
{$ifdef UseOriginal}
if Pos('''', Value) > 0 then
QuoteCh := '#' else
QuoteCh := '''';
{$else}
QuoteCh := '''';
if Pos('''', Value) > 0 then begin
QuoteCh := '';
Value := QuotedStr(Value);
end;
{$endif}
end;
end;
Result := WideFormat('(%s%s%s%s%2:s)', [FieldName, Operator, QuoteCh, VarToWideStr(Value)]);
end;
procedure TForm1.CreateFilterExpr;
var
S : String;
begin
// clear any existing filter
AdoQuery1.Recordset.Filter := adFilterNone;
AdoQuery1.Refresh;
if edFilter.Text = '' then Exit;
S := GetFilterStr(AdoQuery1.FieldByName('Applicant'), edFilter.Text, cbPartialKey.Checked);
// Add the filter expr to Memo1 so we can inspect it
Memo1.Lines.Add(S);
try
AdoQuery1.Recordset.Filter := S;
AdoQuery1.Refresh;
except
end;
end;
procedure TForm1.FilterClick(Sender: TObject);
begin
CreateFilterExpr;
end;
或'
结尾的字段
(如果指定#'
,则包含其中任何一个。(我无法在XE4 / 5中进行测试
因为自从我上周升级到Win10后,我的XE4现在说它没有执照,感谢EMBA!)
我匆匆将此称为解决方案,甚至是解决方案,但它至少值得测试。
我不确定我是否会将loPartialKey
的原始版本称为“{1}}”,因为我不确定
什么用例它对含有引号的值的处理是为了处理。