我有一个带有TADOConnection的TADOTable,并且我想将包含或以用户键入的字符作为开头的职业的表筛选为表单上的TEdit。下面是我目前使用的代码:
procedure TfrmProfessions.Filter;
begin
if edtSearch.text = '' then
begin
dmPAT.ADOTable1.filtered := false;
end
else
begin
with dmPAT.ADOTable1 do
begin
filtered := false;
Filter := 'Profession LIKE ' + quotedstr(edtSearch.text + '%');
filtered := true;
end;
end;
end;我在这条线路上有一个访问权限冲突,我不知道如何解决它:
dmPAT.ADOTable1.filtered := false;我怀疑这是因为,在表单的OnCreate事件中,我清除了TEdit,它在创建TADOTable对象之前调用了这个Filter procedure,但我不确定。
我遇到的另一个错误是Cannot convert type(Null) to type(String)。当我设置过滤器和它的过滤器时,我会得到这个结果,但是没有匹配过滤器的记录。我该怎么解决这个问题?
发布于 2021-08-05 20:59:01
尝试以下几点:
在过程TfrmProfessions.Filter的开头,添加以下行
Caption := dmPat.AdoTable1.FieldByName('Profession').ClassName; // the purpose of this is
// so that you can tell at a glance what field type your Professions field is. which could be important
Assert(Assigned(dmPat)); // Assert generates an exception if its argument is false
// so this checks that dmPat has been created
Assert(Assigned(dmPat.AdoTable1)); // checks that dmPat.AdoTable1 has been created.
Assert(dmPat.AdoTable1.Active); // checks that the table is open如果没有创建db对象,那么就应该清除所有问题。
更新我从您的评论中收集到,您已经解决了异常问题,并期待阅读您是如何做到的。同时,我一直在写以下文章,并决定将其发布,因为它可能会让您和其他人对如何着手调查像您报告的问题有一些深入的了解。
我在D10.4.2中启动了一个新的VCL,并在主表单中添加了一个TAdoConnection、一个TAdoTable、一个TADoCommand、一个连接到AdoTable1的TDataSource、一个TDBGrid和连接到DataSource的TDBNavigator,以及一个搜索文本的TEdit,再加上几个TButtons来调用下面的例程。我没有费心把TAdoTable等放到一个TDataModule中,因为我已经提到了如何处理这个问题。
然后,我使用以下代码创建了一个带有名为AName的文本字段和第一个名为ANumber的测试访问数据库
procedure TForm1.Button3Click(Sender: TObject);
begin
if AdoTable1.Active then
AdoTable1.Close;
AdoCommand1.CommandText :=
{.$define DropTable}
{$ifdef DropTable}
'Drop table MATest';
{$else}
'CREATE TABLE MATest (AName Char(12) , ANumber NUMBER)';
{$endif}
AdoCommand1.Execute;
end;$ifdef是为了让我能够轻松地放下桌子,重新开始。
互联网组中的“公认智慧”似乎是,要用Delphi代码创建一个访问表,您需要使用AdoX ActiveX库,它与Ado Access组件是分开的。然而,TAdoCommand完全能够做到这一点。
然后,我使用以下过程向它添加了一些记录:
procedure TForm1.InsertData;
begin
ADoTable1.Open;
AdoTable1.InsertRecord(['aaa']);
AdoTable1.InsertRecord(['abb']);
AdoTable1.InsertRecord(['bbb']);
end;请注意,这并不是故意为第二个值ANumber字段指定值,因此在数据库文件中,ANumber字段应该接收对缺失值使用的任何值访问(我希望它是Null,但无论如何)。
顺便说一句,在调查问题时,我总是在代码中创建新的记录,这样在程序的每次运行中,这些值都保持不变,并将我想出的数据保存下来输入。
然后,我为AfterScroll添加了AdoTable1事件
procedure TForm1.ADOTable1AfterScroll(DataSet: TDataSet);
var
F : TField;
S : String;
begin
F := AdoTable1.Fields[0];
S := F.AsString;
F := AdoTable1.Fields[1];
S := S + ' / ' + F.AsString;
Caption := S;
end;这样做的目的是迫使对两个字段的字符串表示进行重新评估,以查看表周围的滚动是否引发了您所得到的异常。结果:没有遇到例外情况。
然后,我添加了以下代码来设置筛选
procedure TForm1.edtSearchChange(Sender: TObject);
begin
UpdateFilter;
end;
procedure TForm1.UpdateFilter;
begin
Assert(AdoTable1.Active); // checks that the table is open
AdoTable1.Filtered := False; // we should turn filtering off whether or not
// edSearchText.Text is blank or not
if Trim(edtSearch.Text) <> '' then begin // Trim() removes leading and trailing blanks
AdoTable1.Filter := 'AName LIKE ' + quotedstr('%' + edtSearch.Text + '%');
AdoTable1.Filtered := True;
end;
end;效果很好。aa的过滤器匹配前两行rowa,b匹配第二行和第三行。ADO Filter属性是文档化的这里。
QED。我希望这个例子表明,通过一步一步地构建一个测试项目,而不是试图调试一个已完成的项目,可以更容易地调查像您已经遇到的问题。
对所有这一切进行调查,我注意到了前面我注意到的一些事情: Delphi TAdo组件通过Windows中的MDAC ()层访问数据库,在某些数据库操作失败后,在MDAC层产生异常后,该层的行为就会异常,直到Windows重新启动。我很确定我在这里遇到了这种情况,因为在我成功地进行了过滤之后,出现了一些错误或其他错误,然后我就无法让Ado过滤工作(它总是产生空的结果),直到我重新启动Windows。在那之后,它又恢复了正常工作。
更新2
还有一个悬而未决的问题。为什么如果一个TDBEdit连接到我的ANumber字段(或您的小时1),那么它工作得很好,但是如果我们手动传输字段值inti TEdit或TSpinEdit,我们就会得到字符串转换异常?我用这个代码理解它
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
sedNumber.Text := AdoTable1.FieldByName('ANumber').Value;
end;答案可以在TDBedit单元的Vcl.DBCtrls源代码中找到:
procedure TDBEdit.DataChange(Sender: TObject);
begin
if FDataLink.Field <> nil then
begin
[...]
if FFocused and FDataLink.CanModify then
Text := FDataLink.Field.Text
else
begin
EditText := FDataLink.Field.DisplayText;
if FDataLink.Editing and FDataLink.FModified then
Modified := True;
end;
end [...]注意,这不是访问字段的Value,而是访问它的Text或DisplayText属性,这就是答案。所以,一个比你的修正更简洁的方法就是简单地去做。
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
sedNumber.Text := AdoTable1.FieldByName('ANumber').Text;
end;这可以在没有任何明确的空检查的情况下使异常保持沉默。它起作用是因为
procedure TFloatField.GetText在Data.DB中,当字段包含空值时,显式返回空字符串作为Text值。
发布于 2021-08-07 07:41:52
所以我追踪了问题所在。在我的DataModule中的DataModule事件中,我调用了这个过程:
procedure TdmPAT.DataSource1DataChange(Sender: TObject; Field: TField);
begin
frmProfessions.Show_Record_Values;
end;下面是带有DBGrid的表单中的过程
procedure TfrmProfessions.Show_Record_Values;
begin
with dmPAT.ADOTable1 do
begin
sedPK.value := FieldByName('PK').value;
sedHours.value := FieldByName('Hours').value;
edtProfession.text := fields[1].value;
edtCost.text := floattostrf(FieldByName('Cost').AsFloat, ffcurrency, 12, 2);
if FieldByName('Popular').asboolean then
rgpPopular.ItemIndex := 0
else
rgpPopular.ItemIndex := 1;
end;
end;现在,一旦我过滤了DBGrid,问题就出现了。这不是过滤器本身,但它会导致一个记录用空值显示。然后,当我试图在编辑中显示活动记录(null记录)时,delphi无法将Null转换为sedHours.value:=FieldByName('Hours').value;行中的字符串。
所以我才会犯错误。XD的一些尝试条款应该解决这个问题。我已经重新做了上述过程的代码,它解决了问题
procedure TfrmProfessions.Show_Record_Values;
var
Profession, Hours, Cost, Popular: Tfield;
begin
Profession := dmPAT.ADOTable1.fields[1];
Hours := dmPAT.ADOTable1.fields[2];
Cost := dmPAT.ADOTable1.fields[3];
Popular := dmPAT.ADOTable1.fields[4];
// check if null values
if Profession.value = Null then
edtProfession.text := ''
else
edtProfession.text := Profession.value;
if Hours.value = Null then //The Hours Field is an Integer.
sedHours.value := 0 //sedHours is a TSpinEdit.
else
sedHours.value := Hours.value;
if Cost.value = Null then //The Cost field is Currency in MSAccess.
edtCost.text := floattostrf(0, ffcurrency, 12, 2)
else
edtCost.text := floattostrf(Cost.value, ffcurrency, 12, 2);
if Popular.value = Null then
begin
rgpPopular.ItemIndex := -1;
end
else
begin
case Popular.asboolean of
true:
rgpPopular.ItemIndex := 0;
false:
rgpPopular.ItemIndex := 1;
end;
end;
end;https://stackoverflow.com/questions/68670837
复制相似问题